Logout error on springboot oauth2 - Unable to resolve the Client Registration Identifier - java

Springboot logout endpoint in the springboot oauth2 client implementation is not working
the properties configured are like
spring.security.oauth2.client.registration.cliereg.client-id.yourClientId=null
spring.security.oauth2.client.registration.cliereg.client-secret=YOUR_CLIENT_SECRET
spring.security.oauth2.client.registration.cliereg.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.cliereg.scope=openid, profile, email
spring.security.oauth2.client.provider.cliereg.issuer-uri=https://{yourDomain}/
The configuration
#Autowired
private ClientRegistrationRepository clientRegistrationRepository;
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.oauth2Login(oauth2Login -> oauth2Login.successHandler(
new CustomSuccessHandler()))
.logout(logout -> logout.logoutSuccessHandler(oidcLogoutSuccessHandler()).deleteCookies("JSESSIONID"));
http.cors().configurationSource(request -> corsConfiguration).and().csrf().disable().exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
return http.build();
}
private LogoutSuccessHandler oidcLogoutSuccessHandler() {
OidcLogoutHandler oidcLogoutSuccessHandler = new OidcLogoutHandler(this.clientRegistrationRepository);
LogoutRedirectStrategy redirectStrategy = new LogoutRedirectStrategy();
oidcLogoutSuccessHandler.setRedirectStrategy(redirectStrategy);
return oidcLogoutSuccessHandler;
}
Using the logout endpoint provided from spring security.
The error
{"logTime":"2023-02-18_09:10:51:244.244000000","logTimeEpoch":1676711451244,"logLevel":"ERROR","applicationName":"c2c_user_auth","className":"org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/userauth].[dispatcherServlet]","methodName":"log","lineNo":"175","thread":"http-nio-8195-exec-3","message":"Servlet.service() for servlet [dispatcherServlet] in context with path [/userauth] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Unable to resolve the Client Registration Identifier. It must be provided via #RegisteredOAuth2AuthorizedClient("client1") or #RegisteredOAuth2AuthorizedClient(registrationId = "client1").] with root cause","exception":"java.lang.IllegalArgumentException: Unable to resolve the Client Registration Identifier. It must be provided via #RegisteredOAuth2AuthorizedClient("client1") or #RegisteredOAuth2AuthorizedClient(registrationId = "client1").\n\tat org.springframework.security.oauth2.client.web.method.annotation.OAuth2AuthorizedClientArgumentResolver.resolveArgument(OAuth2AuthorizedClientArgumentResolver.java:119)\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerM
ethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:655)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:121)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticatio
nFilter.java:105)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:218)\n\tat org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:178)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.secu
rity.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)\n\tat org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat

Related

How to handle ResourceAccessException in resttemplate using Spring integration

Here I'm using Spring integration's http outbound gateway to make a http call. I have also added timeout for the call. I have configured the timeout using restemplate. Here whenever it's taking more time then it's throwing an ResourceAccessException but I want to handle that exception and want to send proper msg to the user. Even though I'm using a custom error handler but the exception is not getting handled by that. Below the code where I'm using scatter gather pattern and flow2 is the http call where I want to handle the exception-
#Autowired private RestTemplateConfig resttemplateconfig.
#Bean
public IntegrationFlow mainFlow() {
return flow ->
flow.split()
.channel(c -> c.executor(Executors.newCachedThreadPool()))
.scatterGather(
scatterer ->
scatterer
.applySequence(true)
.recipientFlow(flow1())
.recipientFlow(flow2()),
gatherer ->
gatherer
.releaseLockBeforeSend(true)
.releaseStrategy(group -> group.size() == 1))
.aggregate()
.to(saveCDResponseToDB());
}
#Bean
public IntegrationFlow flow2() {
return flow ->
flow.channel(c -> c.executor(Executors.newCachedThreadPool()))
.handle(
Http.outboundGateway(
"http://localhost:4444/test", resttemplateconfig.restTemplate())
.extractPayload(true)
.httpMethod(HttpMethod.POST)
.expectedResponseType(String.class));
}
//RestTemplateConfig - The Resttemplate Config class where I'm setting the timeout and errorhandler.
#Configuration
public class RestTemplateConfig {
private final int TIMEOUT = (int) TimeUnit.SECONDS.toMillis(6);
#Autowired CustomErrorHandler errorHandler;
#Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setConnectTimeout(TIMEOUT);
requestFactory.setReadTimeout(TIMEOUT);
RestTemplate restTemplate = new RestTemplate(requestFactory);
errorHandler.setMessageConverters(restTemplate.getMessageConverters());
restTemplate.setErrorHandler(errorHandler);
return restTemplate;
}
}
//custom error handler
#Component
public class CustomServiceErrorHandler implements ResponseErrorHandler {
private List<HttpMessageConverter<?>> messageConverters;
#Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return hasError(response.getStatusCode());
}
protected boolean hasError(HttpStatus statusCode) {
return (statusCode.is4xxClientError() || statusCode.is5xxServerError());
}
#Override
public void handleError(ClientHttpResponse httpResponse) throws IOException {
if (httpResponse.getStatusCode().series() == SERVER_ERROR) {
// handle SERVER_ERROR
System.out.println("SERVER_ERROR");
} else if (httpResponse.getStatusCode().series() == CLIENT_ERROR) {
// handle CLIENT_ERROR
System.out.println("CLIENT_ERROR");
} else {
System.out.println("SOME_ERROR");
}
}
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = messageConverters;
}
}
I'm getting below error that I want to handle -
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:4444/test": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
If I'm adding .errorHandler(new CustomErrorHandler()) in Http.outboundgateway then I'm getting error saying -
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flow2' defined in class path resource [example/common/config/SpringIntegrationConfiguration.class]: Initialization of bean failed; nested exception is java.lang.RuntimeException: java.lang.IllegalArgumentException: the 'errorHandler' must be specified on the provided 'restTemplate'
the 'errorHandler' must be specified on the provided 'restTemplate'
It's probably clearly states that such an error handler must be configured on the externally provided RestTemplate.
When an IOException is thrown in the RestTemplate, that error handler is not invoked. See the source code of its doExecute() method:
...
response = request.execute();
handleResponse(url, method, response);
return (responseExtractor != null ? responseExtractor.extractData(response) : null);
}
catch (IOException ex) {
...
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
This type of exceptions has to be handled around that HTTP Gateway call.
See if you can set a custom errorChannel header - enrichHeaders() and handle this error in the dedicated IntegrationFlow. Since you use an ExecutorChannel, the async error handling must have an effect.
Another way (and I recall as showed you before) is to use an ExpressionEvaluatingRequestHandlerAdvice on that Http.outboundGateway() endpoint.
See more in docs: https://docs.spring.io/spring-integration/reference/html/messaging-endpoints.html#message-handler-advice-chain

How to trace queries to oauth2 server with Spring Security?

How I can enable logs to see actual http queries between my Spring Boot app verifying the tokens and the oauth2 server?
spring:
security:
oauth2:
client:
provider:
keycloak:
issuer-uri: https://myhost/idm-services/auth/realms/myrealm
registration:
keycloak:
client-id: myclientid
logging:
level:
org:
springframework:
web:
filter:
CommonsRequestLoggingFilter: DEBUG
security:
oauth2: TRACE
I have this enabled, but I don't see any actual logs to oauth2.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated().and()
.oauth2Login().userInfoEndpoint().oidcUserService(this.oidcUserService());
}
#Bean
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();
return (userRequest) -> {
OidcUser oidcUser = delegate.loadUser(userRequest);
log.debug("User "+oidcUser.toString());
log.debug("UserInfo "+oidcUser.getUserInfo().toString());
log.debug("UserClaims "+oidcUser.getClaims().toString());
log.debug("UserToken "+oidcUser.getIdToken().toString());
final Map<String, Object> claims = oidcUser.getClaims();
final JSONArray groups = (JSONArray) claims.get("org_access");
final Set<GrantedAuthority> mappedAuthorities = groups.stream()
.map(role -> new SimpleGrantedAuthority(""+role))
.collect(Collectors.toSet());
return new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
};
}
there is the security configuration. I'd like to debug the token info transformation in oidcUserService, but the debug lines are not hit during the debug.
No way to trace in org.springframework.security.oauth2.server.resource.authentication
There are just no logging entries there. The only known stuff is to put all logging to trace, then you will see for example HttpConnection calls to ouath servers, that let you clarify what is going on. It is impossible to trace the tokens and data transmitted, so on the stage where you have no option to debug through the remote port, you have no option to understand what was the problem.

Mock user authentication in Spring Boot WebSocket integration tests

I am working on implementing WebSocket integration tests. I cannot get the mock user to be passed to the client.
#WithMockUser(value = "user", roles = "USER")
void test() throws ExecutionException, InterruptedException, TimeoutException {
webSocketStompClient = new WebSocketStompClient(
new SockJsClient(List.of(new WebSocketTransport(new StandardWebSocketClient())))
);
StompSession session = webSocketStompClient
.connect(String.format("ws://localhost:%d/ws", port),
new StompSessionHandlerAdapter() {
}
)
.get(1, SECONDS);
}
Unfortunately, I receive the following error:
TopicInterceptorIT > test() FAILED
java.util.concurrent.ExecutionException at TopicInterceptorIT.java:57
Caused by: org.springframework.messaging.simp.stomp.ConnectionLostException at DefaultStompSession.java:518
2022-01-17 12:04:19.415 WARN [,,,] 44518 --- [ XNIO-1 I/O-9] w.s.h.ExceptionWebSocketHandlerDecorator : Unhandled exception after connection closed for ExceptionWebSocketHandlerDecorator [delegate=LoggingWebSocketHandlerDecorator [delegate=WebSocketMsgEnhancer [delegate=SubProtocolWebSocketHandler[StompSubProtocolHandler[v10.stomp, v11.stomp, v12.stomp]]]]]
org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied
Do I have to manually create the access token and inject it into the request headers? Or is there an approach similar to the #WithMockUser over MockMvc familiar when testing REST endpoints?

OAuth 2 spring Webclient for password grant

In the Rest template I was able to to do the following. I'm trying to implement the same using spring webclient and so far I couldn't find any documentation on how to set this up.
#Bean
public OAuth2RestTemplate createRestTemplate() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
resource.setAccessTokenUri(accessTokenUri);
resource.setClientId(clientID);
resource.setClientSecret(clientSecret);
resource.setGrantType("password");
resource.setScope(Arrays.asList(scope));
resource.setUsername("user");
resource.setPassword("pass");
return new OAuth2RestTemplate(resource);
}

Spring Oauth2RestTemplate error "access_denied"

I need to consume a OAuth2 Rest service with ClientCredential Grant.
I'm using spring security and spring oauth2.
To get the access token i need to call the token uri passing to it a clientId and a password
Basically i need to send a POST with this body
{"clientId":"demo",
"password": "demo_password"
}
and I should get something like that in the response
{
"expiresIn": 3600,
"accessToken": "EF2I5xhL2GU9pAwK",
"statusCode": 200,
"refreshToken": "72BIcYWYhPjuPDGb"
}
I was trying to configure OAuth2RestTemplate in this way
#Configuration
#EnableOAuth2Client
public class RestTemplateConf {
#Value("${ApiClient}")
private String oAuth2ClientId;
#Value("${ApiSecret}")
private String oAuth2ClientSecret;
#Value("${ApiUrl}")
private String accessTokenUri;
#Bean
public OAuth2RestTemplate oAuthRestTemplate() {
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
resourceDetails.setClientId(oAuth2ClientId);
resourceDetails.setClientSecret(oAuth2ClientSecret);
resourceDetails.setAccessTokenUri(accessTokenUri);
resourceDetails.setTokenName("accessToken");
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, new DefaultOAuth2ClientContext());
return restTemplate;
}
}
but i get always
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is error="access_denied", error_description="Error requesting access token."] with root cause
org.springframework.web.client.HttpServerErrorException: 500 Internal Server Error
If i make a POST call to the tokenUri with POSTMAN, for instance, i get the token correctly...

Categories

Resources