Skip to content

Commit 6722a70

Browse files
feature : add conditional Introspector settings based on application.properties
1 parent 27d7cbb commit 6722a70

File tree

10 files changed

+104
-81
lines changed

10 files changed

+104
-81
lines changed

Diff for: README.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
> App-Token based OAuth2 POC built to grow with Spring Boot and ORM
44
5-
- [NOTICE] Test codes will be temporarily non-functional due to the introduction of the Introspector, until the next version.
6-
75
## Supporting Oauth2 Type
86
| ROPC | Authorization Code |
97
|------------------|-------------------------------------------------|
@@ -14,7 +12,7 @@
1412
<dependency>
1513
<groupId>io.github.patternknife.securityhelper.oauth2.api</groupId>
1614
<artifactId>spring-security-oauth2-password-jpa-implementation</artifactId>
17-
<version>3.3.0</version>
15+
<version>3.4.0</version>
1816
</dependency>
1917
```
2018
For v2, using the database tables from Spring Security 5 (only the database tables; follow the dependencies as above):

Diff for: client/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
77
<modelVersion>4.0.0</modelVersion>
88
<groupId>com.patternknife.securityhelper.oauth2.client</groupId>
99
<artifactId>spring-security-oauth2-password-jpa-implementation-client</artifactId>
10-
<version>3.3.0</version>
10+
<version>3.4.0</version>
1111
<packaging>jar</packaging>
1212

1313
<properties>
@@ -48,7 +48,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
4848
<dependency>
4949
<groupId>io.github.patternknife.securityhelper.oauth2.api</groupId>
5050
<artifactId>spring-security-oauth2-password-jpa-implementation</artifactId>
51-
<version>3.3.0</version>
51+
<version>3.4.0</version>
5252
</dependency>
5353

5454
<!-- DB -->

Diff for: client/src/main/java/com/patternknife/securityhelper/oauth2/client/config/securityimpl/guard/SecurityGuardUtil.java

-24
This file was deleted.

Diff for: client/src/main/java/com/patternknife/securityhelper/oauth2/client/config/securityimpl/guard/UserCustomerOnlyImpl.java

+11-8
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,21 @@ public class UserCustomerOnlyImpl {
2828
public Object check(ProceedingJoinPoint joinPoint) throws Throwable {
2929

3030
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
31+
AccessTokenUserInfo accessTokenUserInfo;
32+
if (principal instanceof AccessTokenUserInfo) {
33+
accessTokenUserInfo = ((AccessTokenUserInfo) principal);
34+
}else {
35+
String userName = ((OAuth2IntrospectionAuthenticatedPrincipal) principal).getUsername();
36+
String clientId = ((OAuth2IntrospectionAuthenticatedPrincipal) principal).getClientId();
37+
String appToken = ((OAuth2IntrospectionAuthenticatedPrincipal) principal).getAttribute("App-Token");
3138

32-
String userName =((OAuth2IntrospectionAuthenticatedPrincipal)principal).getUsername();
33-
String clientId =((OAuth2IntrospectionAuthenticatedPrincipal)principal).getClientId();
34-
String appToken = ((OAuth2IntrospectionAuthenticatedPrincipal)principal).getAttribute("App-Token");
3539

40+
OAuth2Authorization oAuth2Authorization = authorizationService.findByUserNameAndClientIdAndAppToken(userName, clientId, appToken);
3641

37-
OAuth2Authorization oAuth2Authorization = authorizationService.findByUserNameAndClientIdAndAppToken(userName, clientId, appToken);
38-
39-
UserDetails userDetails = conditionalDetailsService.loadUserByUsername(userName, clientId);
40-
41-
AccessTokenUserInfo accessTokenUserInfo = ((AccessTokenUserInfo)userDetails);
42+
UserDetails userDetails = conditionalDetailsService.loadUserByUsername(userName, clientId);
4243

44+
accessTokenUserInfo = ((AccessTokenUserInfo) userDetails);
45+
}
4346

4447
if(accessTokenUserInfo != null && (accessTokenUserInfo.getAdditionalAccessTokenUserInfo().getUserType() != AdditionalAccessTokenUserInfo.UserType.CUSTOMER)){
4548
throw new CustomAuthGuardException("ID \"" + accessTokenUserInfo.getUsername() + "\" : Not in Customer Group");

Diff for: client/src/main/java/com/patternknife/securityhelper/oauth2/client/config/securityimpl/introspector/CustomDefaultResourceServerTokenIntrospector.java

+47-8
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,73 @@
11
package com.patternknife.securityhelper.oauth2.client.config.securityimpl.introspector;
22

3+
import io.github.patternknife.securityhelper.oauth2.api.config.security.message.DefaultSecurityUserExceptionMessage;
34
import io.github.patternknife.securityhelper.oauth2.api.config.security.message.ISecurityUserExceptionMessageService;
45
import io.github.patternknife.securityhelper.oauth2.api.config.security.response.error.exception.KnifeOauth2AuthenticationException;
56
import io.github.patternknife.securityhelper.oauth2.api.config.security.serivce.persistence.authorization.OAuth2AuthorizationServiceImpl;
67
import io.github.patternknife.securityhelper.oauth2.api.config.security.serivce.userdetail.ConditionalDetailsService;
78
import org.springframework.beans.factory.annotation.Value;
9+
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
10+
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
811
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
912
import org.springframework.stereotype.Component;
1013
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
11-
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
1214
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
1315

16+
/*
17+
* Set this to your resource servers
18+
* */
1419
@Component
1520
public class CustomDefaultResourceServerTokenIntrospector implements OpaqueTokenIntrospector {
1621

1722
private final OpaqueTokenIntrospector delegate;
1823

24+
/*
25+
* api : resource servers call the authorization server
26+
* database : the database is shared with the authorization server and resource servers
27+
* */
28+
@Value("${patternknife.securityhelper.oauth2.introspection.type}") String introspectionType;
29+
@Value("${patternknife.securityhelper.oauth2.introspection.uri}") String introspectionUri;
30+
@Value("${patternknife.securityhelper.oauth2.introspection.client-id}") String clientId;
31+
@Value("${patternknife.securityhelper.oauth2.introspection.client-secret}") String clientSecret;
32+
33+
34+
private final OAuth2AuthorizationServiceImpl authorizationService;
35+
private final ConditionalDetailsService conditionalDetailsService;
36+
private final ISecurityUserExceptionMessageService iSecurityUserExceptionMessageService;
37+
38+
1939
public CustomDefaultResourceServerTokenIntrospector(
20-
@Value("${security.oauth2.introspection.uri}") String introspectionUri,
21-
@Value("${security.oauth2.introspection.client-id}") String clientId,
22-
@Value("${security.oauth2.introspection.client-secret}") String clientSecret) {
40+
OAuth2AuthorizationServiceImpl authorizationService,
41+
ConditionalDetailsService conditionalDetailsService,
42+
ISecurityUserExceptionMessageService iSecurityUserExceptionMessageService,
43+
@Value("${patternknife.securityhelper.oauth2.introspection.type}") String introspectionType,
44+
@Value("${patternknife.securityhelper.oauth2.introspection.uri}") String introspectionUri,
45+
@Value("${patternknife.securityhelper.oauth2.introspection.client-id}") String clientId,
46+
@Value("${patternknife.securityhelper.oauth2.introspection.client-secret}") String clientSecret) {
2347
this.delegate = new SpringOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret);
48+
this.authorizationService = authorizationService;
49+
this.conditionalDetailsService = conditionalDetailsService;
50+
this.iSecurityUserExceptionMessageService = iSecurityUserExceptionMessageService;
2451
}
2552

2653
@Override
2754
public OAuth2AuthenticatedPrincipal introspect(String token) {
28-
try {
29-
return delegate.introspect(token);
30-
} catch (Exception e) {
31-
throw new KnifeOauth2AuthenticationException(e.getMessage());
55+
if(introspectionType.equals("api")) {
56+
try {
57+
return delegate.introspect(token);
58+
} catch (Exception e) {
59+
throw new KnifeOauth2AuthenticationException(e.getMessage());
60+
}
61+
} else if (introspectionType.equals("database")) {
62+
OAuth2Authorization oAuth2Authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
63+
64+
if(oAuth2Authorization == null || oAuth2Authorization.getAccessToken() == null || oAuth2Authorization.getAccessToken().isExpired()
65+
|| oAuth2Authorization.getRefreshToken() == null || oAuth2Authorization.getRefreshToken().isExpired()){
66+
throw new KnifeOauth2AuthenticationException(iSecurityUserExceptionMessageService.getUserMessage(DefaultSecurityUserExceptionMessage.AUTHENTICATION_TOKEN_FAILURE));
67+
}
68+
return (OAuth2AuthenticatedPrincipal) conditionalDetailsService.loadUserByUsername(oAuth2Authorization.getPrincipalName(), (String) oAuth2Authorization.getAttributes().get("client_id"));
69+
}else{
70+
throw new KnifeOauth2AuthenticationException("Wrong introspection type : " + introspectionType);
3271
}
3372
}
3473
}

Diff for: client/src/main/resources/application.properties

+7-4
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ io.github.patternknife.securityhelper.oauth2.no-app-token-same-access-token=true
7575
spring.mvc.view.prefix=/templates/
7676
spring.mvc.view.suffix=.html
7777

78-
79-
security.oauth2.introspection.uri=http://localhost:8370/oauth2/introspect
80-
security.oauth2.introspection.client-id=client_customer
81-
security.oauth2.introspection.client-secret=12345
78+
# api vs database
79+
# api : resource servers call the authorization server / database : the database is shared with resource servers
80+
# [WARNING] api : some test codes currently NOT working due to the following uri calling.
81+
patternknife.securityhelper.oauth2.introspection.type=database
82+
patternknife.securityhelper.oauth2.introspection.uri=http://localhost:8370/oauth2/introspect
83+
patternknife.securityhelper.oauth2.introspection.client-id=client_customer
84+
patternknife.securityhelper.oauth2.introspection.client-secret=12345

Diff for: client/src/test/java/com/patternknife/securityhelper/oauth2/client/unit/customer/CustomerApiTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ public void setUp(RestDocumentationContextProvider restDocumentationContextProvi
119119
.setControllerAdvice(new GlobalExceptionHandler(iSecurityUserExceptionMessageService))
120120
.setCustomArgumentResolvers(putAuthenticationPrincipal)
121121
.apply(documentationConfiguration(restDocumentationContextProvider).uris()
122-
.withScheme("https")
123-
.withHost("vholic.com")
124-
.withPort(443))
122+
.withScheme("http")
123+
.withHost("localhost")
124+
.withPort(8370))
125125
.addFilters(new CharacterEncodingFilter("UTF-8", true))
126126
.alwaysDo(document)
127127
.build();

Diff for: lib/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
88

99
<groupId>io.github.patternknife.securityhelper.oauth2.api</groupId>
1010
<artifactId>spring-security-oauth2-password-jpa-implementation</artifactId>
11-
<version>3.3.0</version>
11+
<version>3.4.0</version>
1212
<name>spring-security-oauth2-password-jpa-implementation</name>
1313
<description>The implementation of Spring Security 6 Spring Authorization Server for stateful OAuth2 Password Grant</description>
1414
<packaging>jar</packaging>
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,51 @@
1-
package io.github.patternknife.securityhelper.oauth2.api.config.security.provider.resource.introspector;
1+
package io.github.patternknife.securityhelper.oauth2.api.config.security.introspector;
22

33

44
import io.github.patternknife.securityhelper.oauth2.api.config.security.message.DefaultSecurityUserExceptionMessage;
55
import io.github.patternknife.securityhelper.oauth2.api.config.security.message.ISecurityUserExceptionMessageService;
66
import io.github.patternknife.securityhelper.oauth2.api.config.security.response.error.exception.KnifeOauth2AuthenticationException;
77
import io.github.patternknife.securityhelper.oauth2.api.config.security.serivce.persistence.authorization.OAuth2AuthorizationServiceImpl;
88
import io.github.patternknife.securityhelper.oauth2.api.config.security.serivce.userdetail.ConditionalDetailsService;
9+
import org.springframework.beans.factory.annotation.Value;
910
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
1011
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
1112
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
12-
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
1313
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
14-
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
15-
import org.springframework.stereotype.Component;
1614

1715

1816
public class DefaultResourceServerTokenIntrospector implements OpaqueTokenIntrospector {
1917

20-
private OpaqueTokenIntrospector delegate =
21-
new SpringOpaqueTokenIntrospector(
22-
"http://localhost:8370/oauth2/introspect",
23-
"barClient",
24-
"barClientSecret"
25-
);
26-
27-
public DefaultResourceServerTokenIntrospector() {
28-
18+
private final OAuth2AuthorizationServiceImpl authorizationService;
19+
private final ConditionalDetailsService conditionalDetailsService;
20+
private final ISecurityUserExceptionMessageService iSecurityUserExceptionMessageService;
21+
22+
public DefaultResourceServerTokenIntrospector(
23+
OAuth2AuthorizationServiceImpl authorizationService,
24+
ConditionalDetailsService conditionalDetailsService,
25+
ISecurityUserExceptionMessageService iSecurityUserExceptionMessageService,
26+
@Value("${patternknife.securityhelper.oauth2.introspection.type}") String introspectionType,
27+
@Value("${patternknife.securityhelper.oauth2.introspection.uri}") String introspectionUri,
28+
@Value("${patternknife.securityhelper.oauth2.introspection.client-id}") String clientId,
29+
@Value("${patternknife.securityhelper.oauth2.introspection.client-secret}") String clientSecret) {
30+
31+
/*
32+
* @Values will be ignored here. Check CustomResourceServerTokenIntrospector in the sample client folder.
33+
* */
34+
this.authorizationService = authorizationService;
35+
this.conditionalDetailsService = conditionalDetailsService;
36+
this.iSecurityUserExceptionMessageService = iSecurityUserExceptionMessageService;
2937
}
3038

3139
@Override
3240
public OAuth2AuthenticatedPrincipal introspect(String token) {
3341

34-
/* try {
35-
OAuth2AuthenticatedPrincipal principal = delegate.introspect(token);
36-
return principal;
37-
}catch (Exception e){
38-
//throw e;
39-
throw new KnifeOauth2AuthenticationException(e.getMessage());
40-
}*/
41-
return null;
42-
43-
/*OAuth2Authorization oAuth2Authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
42+
OAuth2Authorization oAuth2Authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
4443

4544
if(oAuth2Authorization == null || oAuth2Authorization.getAccessToken() == null || oAuth2Authorization.getAccessToken().isExpired()
4645
|| oAuth2Authorization.getRefreshToken() == null || oAuth2Authorization.getRefreshToken().isExpired()){
4746
throw new KnifeOauth2AuthenticationException(iSecurityUserExceptionMessageService.getUserMessage(DefaultSecurityUserExceptionMessage.AUTHENTICATION_TOKEN_FAILURE));
48-
//return null;
4947
}
5048

51-
return (OAuth2AuthenticatedPrincipal) conditionalDetailsService.loadUserByUsername(oAuth2Authorization.getPrincipalName(), (String) oAuth2Authorization.getAttributes().get("client_id"));*/
49+
return (OAuth2AuthenticatedPrincipal) conditionalDetailsService.loadUserByUsername(oAuth2Authorization.getPrincipalName(), (String) oAuth2Authorization.getAttributes().get("client_id"));
5250
}
5351
}

Diff for: lib/src/main/java/io/github/patternknife/securityhelper/oauth2/api/config/security/server/ServerConfig.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,15 @@
2626
import io.github.patternknife.securityhelper.oauth2.api.config.security.serivce.userdetail.ConditionalDetailsService;
2727
import io.github.patternknife.securityhelper.oauth2.api.config.security.token.generator.CustomDelegatingOAuth2TokenGenerator;
2828

29-
import io.github.patternknife.securityhelper.oauth2.api.config.security.provider.resource.introspector.DefaultResourceServerTokenIntrospector;
29+
import io.github.patternknife.securityhelper.oauth2.api.config.security.introspector.DefaultResourceServerTokenIntrospector;
3030
import jakarta.servlet.ServletException;
3131
import jakarta.servlet.http.HttpServletRequest;
3232
import jakarta.servlet.http.HttpServletResponse;
3333
import lombok.RequiredArgsConstructor;
3434
import org.slf4j.Logger;
3535
import org.slf4j.LoggerFactory;
3636
import org.springframework.beans.factory.annotation.Qualifier;
37+
import org.springframework.beans.factory.annotation.Value;
3738
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3839
import org.springframework.context.annotation.Bean;
3940
import org.springframework.context.annotation.Configuration;
@@ -299,7 +300,12 @@ public AuthenticationEntryPoint iAuthenticationEntryPoint(@Qualifier("handlerExc
299300

300301
@Bean
301302
@ConditionalOnMissingBean(OpaqueTokenIntrospector.class)
302-
public OpaqueTokenIntrospector tokenIntrospector() {
303-
return new DefaultResourceServerTokenIntrospector();
303+
public OpaqueTokenIntrospector tokenIntrospector(OAuth2AuthorizationServiceImpl authorizationService,
304+
ConditionalDetailsService conditionalDetailsService, ISecurityUserExceptionMessageService iSecurityUserExceptionMessageService,
305+
@Value("${patternknife.securityhelper.oauth2.introspection.type:database}") String introspectionType,
306+
@Value("${patternknife.securityhelper.oauth2.introspection.uri}") String introspectionUri,
307+
@Value("${patternknife.securityhelper.oauth2.introspection.client-id}") String clientId,
308+
@Value("${patternknife.securityhelper.oauth2.introspection.client-secret}") String clientSecret) {
309+
return new DefaultResourceServerTokenIntrospector(authorizationService, conditionalDetailsService, iSecurityUserExceptionMessageService, introspectionType, introspectionUri, clientId, clientSecret);
304310
}
305311
}

0 commit comments

Comments
 (0)