spring-projects / spring-projects/spring-security

Support prompt in OIDC flows

Open
#6,815 5 comments 10 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

in: oauth2 type: enhancement
Dominant language
Java
Stars
9.6k
Forks
6.3k
Avg merge
2d 11h
Merged PRs (30d)
52

Description

Summary

Some workflows in OpenID Connect are dependent on being able to use prompt=none to asynchronously refresh the session in the background. In particular, the draft specs for session management depend on the ability to use prompt=none via requests in a hidden iframe (see section 4.1). This is analogous to using isPassive in a SAML2 AuthnRequest.

In order to do that in a web application using spring-security, the OAuth2AuthorizationRequestResolver in use needs to be able to send the prompt=none flag when redirecting a user to an upstream identity provider when non-interactivity is requested by a user. This would also imply that a mechanism would be needed by which clients can request non-interactive session refreshes (which could theoretically share behavior between OIDC & other backing systems such as SAML)

Currently, there is no support for this in DefaultOAuth2AuthorizationRequestResolver, which is used by default when configuring an OpenID Connect login flow. See also some discussion of this in #6742

Configuration

in the WebSecurityConfigurerAdapter:

// this actually comes from Springboot properties:
String loginPage = "/oauth2/authorization/wso2";
// ...
http
    .addFilterAfter(ajaxTimeoutRedirectFilter, ExceptionTranslationFilter.class) // return 401 when attampting unauthenticated AJAX
    .logout().logoutSuccessHandler(oidcLogoutRedirectHandler()).permitAll()  // should go away with support in spring-security 5.2
    .and()
    .authorizeRequests()
      .antMatchers("/censoredPage1.html").hasRole("role1")
      .antMatchers("/censoredPage2.html").hasRole("role2")
      .anyRequest().authenticated() // functional controllers responsible for their own authorization
    .and()
    .oauth2Login()
      .loginPage(loginPage) // only one identity provider should be configured - just go directly there
      .userInfoEndpoint().oidcUserService(userService) // add internal numeric user ID which maps to incoming subject
    .and().and()
    .sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry) // allows session-killing to refresh authorization grants when they change
    .expiredSessionStrategy(new CallFailureSessionInformationExpiredStrategy(loginPage)); // on expired sessions: redirect synchronous requests, 401 async requests

in Spring-boot properties:

# NOTE: you need these two, but they're given by the OIDC provider (WSO2 Identity Server)
# spring.security.oauth2.client.registration.wso2.client-id =
# spring.security.oauth2.client.registration.wso2.client-secret =
# spring.security.oauth2.client.registration.wso2.client-name =
spring.security.oauth2.client.registration.wso2.provider=wso2
# Note well:  The scope list MUST be separated by commas.  There are multiple uses for this and some will work
# if you use spaces but others will fail in significant ways (like bypassing OIDC support and using OAuth2).
spring.security.oauth2.client.registration.wso2.scope=openid,email,phone
spring.security.oauth2.client.registration.wso2.redirect-uri-template=${my_url}/login/oauth2/code/wso2
spring.security.oauth2.client.registration.wso2.client-authentication-method=basic
spring.security.oauth2.client.registration.wso2.authorization-grant-type=authorization_code

spring.security.oauth2.client.provider.wso2.authorization-uri=${wso2.oauth2-root}/authorize
spring.security.oauth2.client.provider.wso2.token-uri=${wso2.issuer}
spring.security.oauth2.client.provider.wso2.user-info-uri=${wso2.oauth2-root}/userinfo
spring.security.oauth2.client.provider.wso2.jwk-set-uri=${wso2.oauth2-root}/jwks
spring.security.oauth2.client.provider.wso2.user-name-attribute=sub

server.port = 8443
my_hostname = https://localhost
my_url = ${my_hostname}:${server.port}
wso2.baseUrl = ${my_hostname}:9443
wso2.oauth2-root = ${wso2.baseUrl}/oauth2
wso2.issuer = ${wso2.oauth2-root}/token
Version

5.1.5 (via spring-boot 2.1.4)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with DefaultOAuth2AuthorizationRequestResolver and the discussion referenced in #6742. Determine how clients should request non-interactive OIDC session refreshes and how that request reaches an upstream identity provider. Done means supporting prompt=none for the described hidden-iframe flow without requiring a custom resolver.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
authentication, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.