diff --git a/compose-branch-deploy.yaml b/compose-branch-deploy.yaml index 05ba4bd181..68694cc0b6 100644 --- a/compose-branch-deploy.yaml +++ b/compose-branch-deploy.yaml @@ -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 diff --git a/war/src/main/java/se/su/dsv/scipro/war/TokenIntrospectionRequestEntityConverter.java b/war/src/main/java/se/su/dsv/scipro/war/TokenIntrospectionRequestEntityConverter.java new file mode 100644 index 0000000000..7b5cfa9e96 --- /dev/null +++ b/war/src/main/java/se/su/dsv/scipro/war/TokenIntrospectionRequestEntityConverter.java @@ -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); + } +} diff --git a/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java b/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java index 90b0b70a61..064728fcbc 100644 --- a/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java +++ b/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java @@ -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, diff --git a/war/src/main/resources/application.properties b/war/src/main/resources/application.properties index 0df6b375e6..7b0b3f2105 100644 --- a/war/src/main/resources/application.properties +++ b/war/src/main/resources/application.properties @@ -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}