Spring Security logout url not found after setting requireCsrfProtectionMatcher - spring

After implementing a csrfProtectionMatcher in my Spring Security Configuration in order to just use CSRF tokens on UI facing REST methods I noticed that the logout method configured via
.and()//
.logout()//
.logoutUrl("/logout")//
.deleteCookies("JSESSIONID")//
was not found anymore (404!).
I figured out that I have to register a logoutRequestMatcher:
.and()//
.logout()//
.logoutUrl("/logout")//
.deleteCookies("JSESSIONID")//
.logoutRequestMatcher(request -> {
RegexRequestMatcher logoutRequest = new RegexRequestMatcher("/logout", null);
if (logoutRequest.matches(request)) {
return true;
}
return false;
})//
Can anyone explain why? :)

Related

Use external api having oauth2 in spring boot

I need to call an external API from my spring boot project. The external API is using OAuth 2 security authentication using authorization_code. I have the client id and secret key, any suggestion would be great.
Tried using SDK provided by DocuSign but while getting access token facing issue as 400 with message consent required.
The easiest way to do this is do download a "quickstart" from DocuSign and pick Java for your language. This does a lot more than just give you Java code, it also configures everything you need for you to be able to make API calls.
https://developers.docusign.com/docs/esign-rest-api/quickstart/
The specific Java code that does Auth Code Grant authentication can be found here:
https://github.com/docusign/code-examples-java/blob/master/src/main/java/com/docusign/core/controller/GlobalControllerAdvice.java
OAuth2AuthenticationToken oauth = (OAuth2AuthenticationToken) authentication;
OAuth2User oauthUser = oauth.getPrincipal();
OAuth2AuthorizedClient oauthClient = authorizedClientService.loadAuthorizedClient(
oauth.getAuthorizedClientRegistrationId(),
oauthUser.getName()
);
if (oauth.isAuthenticated()) {
user.setName(oauthUser.getAttribute("name"));
if (oauthClient != null){
user.setAccessToken(oauthClient.getAccessToken().getTokenValue());
} else {
user.setAccessToken(((OAuth.OAuthToken) oauthUser.getAttribute("access_token")).getAccessToken());
}
if (account.isEmpty()) {
account = Optional.ofNullable(getDefaultAccountInfo(getOAuthAccounts(oauthUser)));
}
OAuth.Account oauthAccount = account.orElseThrow(() -> new NoSuchElementException(ERROR_ACCOUNT_NOT_FOUND));
session.setAccountId(oauthAccount.getAccountId());
session.setAccountName(oauthAccount.getAccountName());
// TODO set this more efficiently with more APIs as they're added in
String basePath = this.getBaseUrl(apiIndex, oauthAccount) + apiIndex.getBaseUrlSuffix();
session.setBasePath(basePath);
}

How to add Custom Token Granter to the new Spring Authorization Server

Hello I am currently using and old Authorization Server with th end of life dependency spring-security-oauth2-autoconfigure and now i would like to migrate to the new Spring Authorization Server
My questions is how can i intercept/override the default Token Granter of the new Spring Authorization Service. In the old version i just extended the AbstractTokenGranter SsoTokenGranter extends AbstractTokenGranter.
I would like to call other services during the token generation and add custom claims/authorities to the JWT Token with user information(Roles, Name, etc..).
Any tipps how i can do this?
I think an OAuth2TokenCustomizer can fit nicely in your use case.
#Bean
public OAuth2TokenCustomizer<JwtEncodingContext> tokenCustomizer(
OidcUserInfoService userInfoService) {
return (context) -> {
if (OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue())) {
OidcUserInfo userInfo = userInfoService.loadUser( // <2>
context.getPrincipal().getName());
context.getClaims().claims(claims ->
claims.putAll(userInfo.getClaims()));
}
};
}
There is a section on the reference docs and a sample that you can use as reference.

How to Implement SAML Single Logout request from a microservice

I have implemented the multi-tenant SAML SSO in my application. I am using a Single Page Application application with the UI in AngularJS, Web API (for assertion URL), and a microservice for creating and handling the SAML requests. I am using the Itfoxtech library in my microservice.
I have implemented the SAML SSO Login successfully and it is working fine. However, I am facing issues while implementing the SAML Single Logout. On SAML Assertion, I am just extracting few claims and returning these to Web API. On Logout, it seems that I need the ClaimsIdentity and HttpContext. I have persisted ClaimsIdentity during the SAML Assertion and re-using it during the Logout but I don't have access to HttpContext. I have created a custom httpContext from DefaultHttpContext and tried to execute the following line of code,
var saml2LogoutRequest = await new Saml2LogoutRequest(config, User).DeleteSession(HttpContext);
but it gives an error,
No sign-out authentication handlers are registered. Did you forget to call AddAuthentication().AddCookies
My question is that how to perform a single logout without using the HttpContext or if it is required then how to manually create it?
Doing logout SAML 2.0 need NameID, NameID format and session index. To achive this you can polulate the ClaimsIdentity with the claims: Saml2ClaimTypes.NameId, Saml2ClaimTypes.NameIdFormat and Saml2ClaimTypes.SessionIndex.
In the case of single logout you only need to validate the request:
Saml2StatusCodes status;
var requestBinding = new Saml2PostBinding();
var logoutRequest = new Saml2LogoutRequest(config, User);
try
{
requestBinding.Unbind(Request.ToGenericHttpRequest(), logoutRequest);
status = Saml2StatusCodes.Success;
//TODO handle logout
}
catch (Exception exc)
{
// log exception
Debug.WriteLine("SingleLogout error: " + exc.ToString());
status = Saml2StatusCodes.RequestDenied;
}
and respond:
var responsebinding = new Saml2PostBinding();
responsebinding.RelayState = requestBinding.RelayState;
var saml2LogoutResponse = new Saml2LogoutResponse(config)
{
InResponseToAsString = logoutRequest.IdAsString,
Status = status,
};
return responsebinding.Bind(saml2LogoutResponse).ToActionResult();
You do not need to call the DeleteSession(HttpContext) but you need to handle logout somehow.

How to ignore ssl on the microprofile rest client of quarkus

I'd like to ignore hostname verify and ignore client side certification validation while calling https rest api with RestClient
I cannot find a way to do it without using builder.
and seems that the hostverifier does not work at all.
public interface RHPAMRestClient {
// Starts a new process instance of a specified process.
#POST
#Path("/server/containers/{containerId}/processes/{processId}/instances")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
Object startProcess(#PathParam String containerId, #PathParam String processId, Object req);
}
RHPAMRestClient c = RestClientBuilder.newBuilder()
.baseUri(new URI(""))
.sslContext(SSLContexts.custom().loadTrustMaterial((chain, authType) -> true).build())
.hostnameVerifier((hostname, session) -> {
System.err.println("hostname verifier");
return true;
})
.build(RHPAMRestClient.class);
c.startProcess("", "", null);
It seems that there is a missconfiguration in Quarkus.
According to the documents, https://quarkus.io/guides/native-and-ssl, ssl support should be enabled when using quarkus-rest-client and the property quarkus.ssl.native should be true.
But it seems that it is false, this causes the org.jboss.resteasy.microprofile.client.RestClientBuilderImpl to override your settings
if (!SSL_ENABLED) {
resteasyClientBuilder.httpEngine((new URLConnectionClientEngineBuilder()).resteasyClientBuilder(resteasyClientBuilder).build());
resteasyClientBuilder.sslContext((SSLContext)null);
resteasyClientBuilder.trustStore((KeyStore)null);
resteasyClientBuilder.keyStore((KeyStore)null, "");
}
Forcing the property to true will magically make everything work as expected.
So, just set
quarkus.ssl.native=true in your application.properties file
(using Quarkus 1.3.1.Final)

Grails & Spring Security - Saved request - Empty parameters and unbound command object

I have a controller which accepts a form POST. This method/action of the controller is protected by Spring Security. In this situation the user's session has expired and they click the submit button.
Spring security is creating a saved request and redirecting the user to the login page. Upon logging in Spring Security is redirecting to the POST url for the form. However, params within the controller method/action is empty (except for controller and action name) and the command object is unpopulated.
Using the some simple code within the onInteractiveAuthenticationEvent I can see that the Saved Request has all the parameters in the Parameter Map.
grails.plugins.springsecurity.onInteractiveAuthenticationSuccessEvent = { e, appCtx ->
def request = org.codehaus.groovy.grails.plugins.springsecurity.SecurityRequestHolder.getRequest()
def response = org.codehaus.groovy.grails.plugins.springsecurity.SecurityRequestHolder.getResponse()
org.springframework.security.web.savedrequest.SavedRequest savedRequest = new org.springframework.security.web.savedrequest.HttpSessionRequestCache().getRequest(request, response);
println savedRequest
if (savedRequest) {
savedRequest.getParameterMap().each { k, v ->
println "${k}: ${v}"
}
}
}
Any ideas as to why the params and command object for the controller action/method are empty and unbound? I would expect that after successful login the saved request would be used to populate both params and then in turn the command to bind to the parameters.
I have tested this with both Grails 2.0.4, Spring Security Core Plugin 1.2.7.3 as well as Grails 2.4.2 and Spring Security Core Plugin 2.0-RC3.
Since this appears to be left to you (the user of Spring Security) to implement I decided to do so using a Grails filter. I know it could have been implemented using a Spring Security filter and placed in the filter chain (as indicated by the Spring Security API documentation) but I needed to move on to other things.
So, here is an example of what I did.
package com.example
class SavedRequestFilters {
def filters = {
// only after a login/auth check to see if there are any saved parameters
savedRequestCheck(controller: 'login', action: 'auth') {
after = {
org.springframework.security.web.savedrequest.SavedRequest savedRequest = new org.springframework.security.web.savedrequest.HttpSessionRequestCache().getRequest(request, response)
if (savedRequest) {
// store the parameters and target uri into the session for later use
session['savedRequestParams'] = [
uri: savedRequest.getRedirectUrl(),
data: savedRequest.getParameterMap()
]
}
}
}
all(controller:'*', action:'*') {
before = {
// if the session contains dr saved request parameters
if (session['savedRequestParams']) {
def savedRequestParams = session['savedRequestParams']
// only if the target uri is the current will the params be needed
if (savedRequestParams.uri.indexOf("/${controllerName}/") > -1) {
savedRequestParams.data.each { k, v ->
params[k] = v.join(",")
}
// clear the session storage
session['savedRequestParams'] = null
}
}
}
}
}
}

Resources