From 742fc3b721e700582db45759af826efd8f39d033 Mon Sep 17 00:00:00 2001
From: Nico Athanassiadis <nico@dsv.su.se>
Date: Tue, 25 Mar 2025 13:44:38 +0100
Subject: [PATCH 1/2] Use OAuth2 Token Introspection during login

Basically the same as: https://gitea.dsv.su.se/DMC/scipro/pulls/141
---
 ...enIntrospectionRequestEntityConverter.java | 42 +++++++++++++++++++
 .../configuration/SeshatConfiguration.java    | 29 +++++++++++++
 .../CustomOAuth2loginSuccessHandler.java      |  2 +-
 src/main/resources/application.properties     |  2 +-
 4 files changed, 73 insertions(+), 2 deletions(-)
 create mode 100644 src/main/java/se/su/dsv/seshat/TokenIntrospectionRequestEntityConverter.java
 create mode 100644 src/main/java/se/su/dsv/seshat/configuration/SeshatConfiguration.java

diff --git a/src/main/java/se/su/dsv/seshat/TokenIntrospectionRequestEntityConverter.java b/src/main/java/se/su/dsv/seshat/TokenIntrospectionRequestEntityConverter.java
new file mode 100644
index 0000000..794b84a
--- /dev/null
+++ b/src/main/java/se/su/dsv/seshat/TokenIntrospectionRequestEntityConverter.java
@@ -0,0 +1,42 @@
+package se.su.dsv.seshat;
+
+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;
+
+import java.net.URI;
+import java.util.Collections;
+
+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/src/main/java/se/su/dsv/seshat/configuration/SeshatConfiguration.java b/src/main/java/se/su/dsv/seshat/configuration/SeshatConfiguration.java
new file mode 100644
index 0000000..aa00f63
--- /dev/null
+++ b/src/main/java/se/su/dsv/seshat/configuration/SeshatConfiguration.java
@@ -0,0 +1,29 @@
+package se.su.dsv.seshat.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
+import se.su.dsv.seshat.TokenIntrospectionRequestEntityConverter;
+
+@Configuration
+public class SeshatConfiguration {
+
+    // 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;
+    }
+
+
+    // TokenIntrospectionRequestEntityConverter
+    // TokenIntrospectionRequestEntityConverter
+}
diff --git a/src/main/java/se/su/dsv/seshat/services/CustomOAuth2loginSuccessHandler.java b/src/main/java/se/su/dsv/seshat/services/CustomOAuth2loginSuccessHandler.java
index b1cb137..805ac55 100644
--- a/src/main/java/se/su/dsv/seshat/services/CustomOAuth2loginSuccessHandler.java
+++ b/src/main/java/se/su/dsv/seshat/services/CustomOAuth2loginSuccessHandler.java
@@ -35,7 +35,7 @@ public class CustomOAuth2loginSuccessHandler implements AuthenticationSuccessHan
         String email = oAuth2User.getAttribute("mail") != null ? oAuth2User.getAttribute("mail") : "no-email";
 
 
-        if(!userService.existsByUsername(oAuth2User.getAttribute("principal"))) {
+        if(!userService.existsByUsername(username)) {
             userService.registerUser(username, email);
         }
         response.sendRedirect(redirectUrl);
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index cbca5ec..b200329 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -32,7 +32,7 @@ spring.jpa.show-sql=false
 # OAuth2 properties, remember if you change the registration.provider the provider properties must be updated
 spring.security.oauth2.client.provider.docker.authorization-uri=http://localhost:51337/authorize
 spring.security.oauth2.client.provider.docker.token-uri=http://localhost:51337/exchange
-spring.security.oauth2.client.provider.docker.user-info-uri=http://localhost:51337/verify
+spring.security.oauth2.client.provider.docker.user-info-uri=http://localhost:51337/introspect
 spring.security.oauth2.client.provider.docker.user-name-attribute=sub
 spring.security.oauth2.client.registration.seshat.client-id=seshat
 spring.security.oauth2.client.registration.seshat.client-secret=n0tS3cr3t
-- 
2.39.5


From 811f6ba4b7ea6859706e0c47299e2b3cfd68c3f6 Mon Sep 17 00:00:00 2001
From: Andreas Svanberg <andreass@dsv.su.se>
Date: Tue, 25 Mar 2025 15:45:29 +0100
Subject: [PATCH 2/2] Minor cleanup

---
 .../se/su/dsv/seshat/configuration/SeshatConfiguration.java   | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/src/main/java/se/su/dsv/seshat/configuration/SeshatConfiguration.java b/src/main/java/se/su/dsv/seshat/configuration/SeshatConfiguration.java
index aa00f63..c37b80d 100644
--- a/src/main/java/se/su/dsv/seshat/configuration/SeshatConfiguration.java
+++ b/src/main/java/se/su/dsv/seshat/configuration/SeshatConfiguration.java
@@ -22,8 +22,4 @@ public class SeshatConfiguration {
         defaultOAuth2UserService.setRequestEntityConverter(new TokenIntrospectionRequestEntityConverter());
         return defaultOAuth2UserService;
     }
-
-
-    // TokenIntrospectionRequestEntityConverter
-    // TokenIntrospectionRequestEntityConverter
 }
-- 
2.39.5