I am very new to oauth and especially spring oauth2. Using basic spring oauth basic authentication it’s success.
Now I want to custom url and authentication method:
curl –location ‘http://localhost:27113/api/token/b2b
X-TIMESTAMP : DateTime with timezone, which follows the ISO-8601 standard
X-CLIENT-KEY : client_id
X-SIGNATURE : Signature Asymmetric
Content-Type : application/json
{
“grantType”: “client_credentials”
}
=================================
Signature asymmetric :
Generate Signature Asymmetric
SHA256withRSA is used to generate the signature with your Private Key as the key
X-SIGNATURE = SHA256withRSA(PrivateKey, StringToSign)
Note = X-SIGNATURE should be encoded by Base64
The StringToSign will be a colon-separated list derived from some request data as below :
StringToSign = client_ID+”|”+X-TIMESTAMP
///AuthorizationServiceConfigurerAdapterImpl.java
public class AuthorizationServiceConfigurerAdapterImpl extends AuthorizationServerConfigurerAdapter{
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenStore JdbcTokenStore;
@Autowired
private DataSource dataSource;
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.jdbc(dataSource);
//.inMemory().withClient("test").accessTokenValiditySeconds(3600);
}
@Override
public void configure(
AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(JdbcTokenStore)
.pathMapping("/oauth/token" , "/api/oauth/token")
.pathMapping("/oauth/authorize" , "/api/oauth/authorize")
.pathMapping("/oauth/check_token" , "/api/oauth/check_token")
.pathMapping("/oauth/confirm_access" , "/api/oauth/confirm_access")
.pathMapping("/oauth/error" , "/api/oauth/error")
.pathMapping("/oauth/token" , "/api/oauth/token")
.authenticationManager(authenticationManager);
endpoints.addInterceptor((HandlerInterceptor) new SignatureVerificationFilter())
//endpoints.addInterceptor(new SignatureVerificationInterceptor())
.pathMapping("/oauth/token", "/api/token/b2b");
}
@Bean
public FilterRegistrationBean filterRegistrationBean() throws Exception {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
SignatureVerificationFilter securityFilter = new SignatureVerificationFilter(publicKey());
registrationBean.setFilter(securityFilter);
registrationBean.addUrlPatterns("/api/token/b2b");
registrationBean.setOrder(1);
return registrationBean;
}
@Bean
public PublicKey publicKey() throws Exception {
return loadPublicKey();
}
}
///SignatureVerificationFilter.java
public class SignatureVerificationFilter extends OncePerRequestFilter {
@Autowired
private SignatureVerificationService signatureVerificationService;
private PublicKey publicKey;
public SignatureVerificationFilter(PublicKey publicKey) {
// TODO Auto-generated constructor stub
this.publicKey = publicKey;
}
public SignatureVerificationFilter() {
// TODO Auto-generated constructor stub
}
//@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
return request.getHeader("X-CLIENT-KEY");
}
//@Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
return request.getHeader("X-SIGNATURE");
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String clientId = request.getHeader("X-CLIENT-KEY");
String timestamp = request.getHeader("X-TIMESTAMP");
String signature = request.getHeader("X-SIGNATURE");
try {
if (!signatureVerificationService.verifySignature(clientId, timestamp, signature)) {
throw new AuthenticationException("Invalid signature") {
private static final long serialVersionUID = 1L;};
}
filterChain.doFilter(request, response);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
response.getWriter().write("{"responseCode":"4017300","responseMessage":"Unauthorized. [Signature]"}");
}
}
}
//SignatureVerificationService.java
public class SignatureVerificationService {
@Autowired
private ClientDetailsRepository clientDetailsRepository;
public boolean verifySignature(String clientId, String timestamp, String signature) throws JOSEException, ParseException {
ClientDetails client = clientDetailsRepository.findByClientId(clientId);
if (client == null) {
return false;
}
String stringToSign = clientId + "|" + timestamp;
// Base64 decode the signature
byte[] decodedSignature = Base64.getDecoder().decode(signature);
// Create JWSObject to represent the JWT
JWSObject jwsObject = JWSObject.parse(new String(decodedSignature));
// Parse the public key stored in the database
RSAPublicKey publicKey = (RSAPublicKey) RSAKey.parse(client.getPublicKey()).toPublicKey();
// Create an RSASSAVerifier with the public key
RSASSAVerifier verifier = new RSASSAVerifier(publicKey);
// Verify the signature
return jwsObject.verify(verifier) && jwsObject.getPayload().toString().equals(stringToSign);
}
}
All credentials: public key, and private key is correct. But it’s got error:
2024-08-12 15:14:54,809 DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher [http-nio-27113-exec-6] Checking match of request : ‘/api/token/b2b’; against ‘/api/token/b2b’
2024-08-12 15:14:54,810 DEBUG org.springframework.security.access.intercept.AbstractSecurityInterceptor [http-nio-27113-exec-6] Secure object: FilterInvocation: URL: /api/token/b2b; Attributes: [fullyAuthenticated]
2024-08-12 15:14:54,810 DEBUG org.springframework.security.access.intercept.AbstractSecurityInterceptor [http-nio-27113-exec-6] Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2024-08-12 15:14:54,810 DEBUG org.springframework.security.access.vote.AffirmativeBased [http-nio-27113-exec-6] Voter: org.springframework.security.web.access.expression.WebExpressionVoter@4866e6fa, returned: -1
2024-08-12 15:14:54,810 DEBUG org.springframework.security.web.access.ExceptionTranslationFilter [http-nio-27113-exec-6] Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
All credentials: public key, and private key is correct. But it’s got error:
2024-08-12 15:14:54,809 DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher [http-nio-27113-exec-6] Checking match of request : ‘/api/token/b2b’; against ‘/api/token/b2b’
2024-08-12 15:14:54,810 DEBUG org.springframework.security.access.intercept.AbstractSecurityInterceptor [http-nio-27113-exec-6] Secure object: FilterInvocation: URL: /api/token/b2b; Attributes: [fullyAuthenticated]
2024-08-12 15:14:54,810 DEBUG org.springframework.security.access.intercept.AbstractSecurityInterceptor [http-nio-27113-exec-6] Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2024-08-12 15:14:54,810 DEBUG org.springframework.security.access.vote.AffirmativeBased [http-nio-27113-exec-6] Voter: org.springframework.security.web.access.expression.WebExpressionVoter@4866e6fa, returned: -1
2024-08-12 15:14:54,810 DEBUG org.springframework.security.web.access.ExceptionTranslationFilter [http-nio-27113-exec-6] Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
justsun is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.