Use OAuth 2.0 Token Introspection during log in (#141)
Currently, it uses an endpoint similar to OpenID Connect UserInfo but with some differences. The endpoint does not require the "openid" scope for example. There is an ongoing effort to replace the OAuth 2.0 authorization server with a more standard compliant one which would break the endpoint (since it would require the "openid" scope). It is currently not possible to request the "openid" scope to future-proof since Spring would act differently if that scope is present and assume full OpenID Connect. That leads to requiring an id token to have been issued which the current authorization server does not do. To get around this the implementation is changed to use a standard compliant Token Introspection endpoint to get access to the subject of the access token (which is the only part that's necessary right now). Since the endpoint is standard compliant it will work with any future authorization server. It may be necessary to run `docker compose up --build` to get the latest version of the Toker containers. Reviewed-on: #141 Reviewed-by: Nico Athanassiadis <nico@dsv.su.se> Co-authored-by: Andreas Svanberg <andreass@dsv.su.se> Co-committed-by: Andreas Svanberg <andreass@dsv.su.se>
This commit is contained in:
parent
9fa699ed83
commit
e95421b8f2
@ -15,7 +15,7 @@ services:
|
||||
- JDBC_DATABASE_PASSWORD=scipro
|
||||
- OAUTH2_AUTHORIZATION_URI=https://oauth2-${VHOST}/authorize
|
||||
- OAUTH2_TOKEN_URI=https://oauth2-${VHOST}/exchange
|
||||
- OAUTH2_USER_INFO_URI=https://oauth2-${VHOST}/verify
|
||||
- OAUTH2_USER_INFO_URI=https://oauth2-${VHOST}/introspect
|
||||
- OAUTH2_CLIENT_ID=scipro_client
|
||||
- OAUTH2_CLIENT_SECRET=scipro_secret
|
||||
- OAUTH2_RESOURCE_SERVER_ID=scipro_api_client
|
||||
|
@ -0,0 +1,42 @@
|
||||
package se.su.dsv.scipro.war;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
public class TokenIntrospectionRequestEntityConverter implements Converter<OAuth2UserRequest, RequestEntity<?>> {
|
||||
|
||||
private static final MediaType FORM_URL_ENCODED = MediaType.valueOf(
|
||||
MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"
|
||||
);
|
||||
|
||||
@Override
|
||||
public RequestEntity<?> convert(OAuth2UserRequest userRequest) {
|
||||
ClientRegistration clientRegistration = userRequest.getClientRegistration();
|
||||
|
||||
URI uri = UriComponentsBuilder.fromUriString(
|
||||
clientRegistration.getProviderDetails().getUserInfoEndpoint().getUri()
|
||||
)
|
||||
.build()
|
||||
.toUri();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setBasicAuth(clientRegistration.getClientId(), clientRegistration.getClientSecret());
|
||||
headers.setAccept(Collections.singletonList(MediaType.ALL));
|
||||
headers.setContentType(FORM_URL_ENCODED);
|
||||
|
||||
MultiValueMap<String, String> formParameters = new LinkedMultiValueMap<>();
|
||||
formParameters.add(OAuth2ParameterNames.TOKEN, userRequest.getAccessToken().getTokenValue());
|
||||
return new RequestEntity<>(formParameters, headers, HttpMethod.POST, uri);
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import se.su.dsv.scipro.SciProApplication;
|
||||
import se.su.dsv.scipro.crosscutting.ForwardPhase2Feedback;
|
||||
@ -67,6 +68,21 @@ public class WicketConfiguration {
|
||||
return http.build();
|
||||
}
|
||||
|
||||
// Stop gap measure to switch to Token Introspection instead of OIDC UserInfo
|
||||
// endpoint. This is necessary because the UserInfo endpoint will in soon require
|
||||
// the "openid" scope, which is not granted to our clients. Unfortunately we can't
|
||||
// request the scope because that makes Spring require an id token in the token
|
||||
// exchange which is not granted at the moment.
|
||||
//
|
||||
// Once a new authorization server is in place we can remove this bean and use
|
||||
// straight up id tokens with "openid" scope.
|
||||
@Bean
|
||||
public DefaultOAuth2UserService defaultOAuth2UserService() {
|
||||
DefaultOAuth2UserService defaultOAuth2UserService = new DefaultOAuth2UserService();
|
||||
defaultOAuth2UserService.setRequestEntityConverter(new TokenIntrospectionRequestEntityConverter());
|
||||
return defaultOAuth2UserService;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CurrentUserFromSpringSecurity currentUserFromSpringSecurity(
|
||||
UserService userService,
|
||||
|
@ -22,7 +22,7 @@ spring.security.oauth2.resourceserver.opaquetoken.client-secret=${OAUTH2_RESOURC
|
||||
spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=${OAUTH2_RESOURCE_SERVER_INTROSPECTION_URI:http://localhost:59733/introspect}
|
||||
|
||||
# Log in via local OAuth 2 authorization server
|
||||
spring.security.oauth2.client.provider.docker.user-info-uri=${OAUTH2_USER_INFO_URI:http://localhost:59734/verify}
|
||||
spring.security.oauth2.client.provider.docker.user-info-uri=${OAUTH2_USER_INFO_URI:http://localhost:59734/introspect}
|
||||
spring.security.oauth2.client.provider.docker.user-name-attribute=sub
|
||||
spring.security.oauth2.client.provider.docker.token-uri=${OAUTH2_TOKEN_URI:http://localhost:59734/exchange}
|
||||
spring.security.oauth2.client.provider.docker.authorization-uri=${OAUTH2_AUTHORIZATION_URI:http://localhost:59734/authorize}
|
||||
|
Loading…
x
Reference in New Issue
Block a user