Context - Spring + OAuth2
Securing the ID Token
Current (Keycloak) Auth Flow
Proposed UserManagement OAuth2 Flow
To implement a more generic OAuth2 flow, the filter chain in the web security config will be changed to use the Spring Security oauth2Login provider as below:
httpSecurity.csrf() .and() .authorizeRequests() .anyRequest().authenticated() .and() .oauth2Login() .successHandler(successHandler);
In order to create a reusable approach, a shared success handler can be created or adapted from an existing class to achieve the following:
Retrieve the appropriate claim from the token to be matched with the username in the profile service
Verify the user exists, and retrieve the user’s roles and principles for authorization
Set the calling service’s security context with the retrieved authorities (do we want to do this?)#
A high level idea of this can be seen below:
A more specific example idea of a real implementation can be split into two parts:
Shared Components
SharedAuthencticationSuccessHandler
(implements AuthenticationSuccessHandler
) (needs new name)Instantiated with following dependencies/params:
SecurityContext
(is this bad?) - for setting granted authoritiesJwtUtil
(another shared component, see below) - for decoding token to retrieve user detailsUserDetailsService
- for retrieving user details
Does the following in its
onAuthenticationSuccess
method:Decodes token to find username (email) using
JwtUtil
Fetches user details from
UserDetailsService
Extracts granted authorities from
UserInfo
and sets them inSecurityContext
Authorization can now be performed on controllers etc within the calling service
JwtUtil
class (again, needs a better name)Instantiated with the following dependencies/params:
jwkSetUri
String configured as an application propertyjwtIssuer
String configured as an application propertyusernameClaim
String configured as an application property (this is because we use email as the username)creates a
NimbusJwtDecoder
Bean fromjwkSetUri
andjwtIssuer
Does the following:
Method to retrieve the username from the token
UserDetailsService
- Already exists, fetches user infor by user name
Service-Specific Configuration
Given the above, each service would need to be configured with the following application properties:
jwkSetUri
jwtIssuer
usernameClaim
& any provider-specific (e.g. cognito) configuration required by spring framework to perform the authentication step in
oauth2Login()
and would need to instantiate the following beans:
SharedAuthencticationSuccessHandler
(injected intosuccessHandler
)JwtUtil
(injected into the above)
In theory, this implementation should support any OAuth2 Provider with only configuration changes
Tickets
One Ticket to implement the new Shared Components (enough of a vertical slice?)
One Ticket per service to switch over configuration (possibly with different subtasks depending on authorization/redirect requirements of each service)
Add Comment