Spring Security loginPage Vs loginProcessingURL - spring

what is the difference between loginPage vs loginProcessingURL.
.formLogin().loginPage("/login").usernameParameter("phone-number").passwordParameter("password")
Seems to be loginProcessingURL is like post method once user submits the data in the login page but when I remove also it is working fine. What is the significance of loginProcessingURL and how does it differ from loginPage?

The line loginPage("/login") instructs Spring Security
when authentication is required, redirect the browser to /login
we are in charge of rendering the login page when /login is requested
when authentication attempt fails, redirect the browser to
/login?error (since we have not specified otherwise)
we are in charge of rendering a failure page when /login?error is
requested
when we successfully logout, redirect the browser to /login?logout
(since we have not specified otherwise)
we are in charge of rendering a logout confirmation page when
/login?logout is requested
AND
.loginProcessingUrl("/login/process")
tells Spring Security to process the submitted credentials when sent the specified path and, by default, redirect user back to the page user came from. It will not pass the request to Spring MVC and your controller.
Refer documentation

Purpose of loginPage()
The loginPage() tells the framework where the user will be redirected when login is required. For example when you are not authorized to the page, you get redirected to this page. This page performs the login activity, for example when you implement a loginForm() or oauth2Login() like in my code using Google OAuth2,this page redirects to google login.
http.anonymous().and()
.authorizeRequests().antMatchers("/images**").permitAll().and()
.authorizeRequests().anyRequest().authenticated().and()
.oauth2Login()
.successHandler((request, response, authentication) -> {
request.authenticate(response);
})
.loginPage("/oauth2/authorization/google")
.loginProcessingUrl("/login")
Purpose of loginProcessingUrl()
The loginProcessingUrl() is the method that automatically set the rule antMatchers("/thisUrl").permitAll() to this URL so that when the response is returned (code, state, token, etc.) will be allowed to be GETed and this response is processed as you can see in the authenticate method of the request. Something more important is that this loginProcessingUrl() tells that the response should be processed to this URL. Without this the request.authenticate(response) will not be executed and authentication will not be returned or otherwise you implement another algorithm.

May the following code segment from spring security source code will help you:
loginPage the login page to redirect to if authentication is required
loginProcessingUrl the URL to validate username and password
DEFAULT_LOGIN_PAGE_URL = "/login"
/**
* Updates the default values for authentication.
*
* #throws Exception
*/
protected final void updateAuthenticationDefaults() {
if (loginProcessingUrl == null) {
loginProcessingUrl(loginPage);
}
//...
}

Related

how to make custom login with token in JSF with Spring Security

I've requirement to login with username and password then upon valid credentials to send token on his mail and ask him to enter the token.
I'm setting Login.xhtml page as login page as follows, but the result I'm any form submission goes to authority filter not to the bean, I need it to capture the action in the managed bean first to validate inputs then send him token and validate his input.
http.authorizeRequests()
.antMatchers("/", "/login.xhtml", "/finance.xhtml", "/WEB-INF/errorpages/**",
"/javax.faces.resource/**")
.permitAll().anyRequest().fullyAuthenticated().and().formLogin().loginPage("/login.xhtml")
.defaultSuccessUrl("/index.xhtml").failureUrl("/login.xhtml?authfailed=true").permitAll().and().logout()
.logoutSuccessUrl("/login.xhtml").logoutUrl("/j_spring_security_logout").and().csrf().disable();
I changed loginprocessingurl to fake url and kept login page, so it's redirecting to login page if not logged in and then I'm doing normal stuff to authenticate the user then use authmanger to auth, it's working fine but not optimal specially I'm making explicit redirect to home (not the page the user was accessing) ***Authentication auth = authenticationManager .authenticate(new UsernamePasswordAuthenticationToken(email, token)); SecurityContextHolder.getContext().setAuthentication(auth); Faces.redirect("/index.xhtml");

Spring Boot/Security - Custom 404 page

I have created a custom 404 error page in my Spring Boot app, I also use Spring Security and I have an authentication entry point with a number of authorised URL's (error page included in that list).
What I'm finding is that if I enter a URL that doesn't exist the authentication entry point intercepts the request as it isn't an authorised URL and I end up back at my login page instead of the custom 404 error page. Any ideas?
Basic example of what I have in the security config
http
.csrf().disable()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
.and()
.authorizeRequests().antMatchers("/login", "/error-404")
Here is what Spring Security will do when you invoke /invalid-url
If /invalid-url is secure (default)
Store the request (/invalid-url -> session)
Invoke authentication entry point
Redirect to /login
User will authenticate
Upon successful authentication, redirect to stored request /invalid-url
Page not found - redirect to error handler
If /invalid-url is not secure
Page not found - redirect to error handler
So basically, you'd need to declare all your non secure URLs if you want the second flow, directly go to 404 page
.mvcMatchers("/login", "/error-404/**", "/invalid-url/**").permitAll()
Obviously doing this:
.anyRequests().permitAll()
as the last statement will solve your use case, it is also dangerous. You have then explicitly map out any endpoint that must be secured. And if you forget one, that endpoint will be left exposed.

SAMLException: InResponseToField of the Response doesn't correspond to sent message

We are working on an application, which is protected with spring security saml.
Authentication works fine, but there is one problem with the following workflow in production environment.
user requests the unprotected address www.server.com
response is a html page with an inline script that changes window.location.href to the saml protected page (service provider) www.server.com/app/action?param1=value1&param2=value2
spring saml detects that authentication is needed and redirects the user to the login form (identity provider) on www.login-server.com
at this point the login form is the first page that is displayed to the user
user adds this login page as bookmark (including saml related url params for this http session) www.login-server.com/adfs/ls/?SAMLRequest=xxx&SigAlg=xxx&Signature=arGdsZwJtHzTDjQP1oYqbjNO
user works with the application...
at the next day the user opens this bookmark and login
IdP redirects to the SP but the belonging http session has already expired
Now we get the following exception in our application:
org.opensaml.common.SAMLException: InResponseToField of the Response doesn't correspond to sent message arGdsZwJtHzTDjQP1oYqbjNO
Any ideas how to handle this workflow so the user can use the application after successful login?
Thanks for your answers!
We have solved our issue with following changes to the spring saml configuration:
In bean with id successRedirectHandler (org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler) we set the defaultTargetUrl to the init-Action of our application (including all request parameters). This url will be automatically used in case of IdP initiated SSO.
In Bean with id contextProvider (org.springframework.security.saml.context.SAMLContextProviderLB) we set storageFactory to org.springframework.security.saml.storage.EmptyStorageFactory. This disables the check of the InResponseToField.
When you applicate generated an AuthnRequest, the request has an ID which your application somehow keeps. The corresponding response from IdP must have InResponseTo attribute set to that same ID value so that your application can verify that the response is meant to be for the request it sent.
However, when your user bookmarked the adfs link that contains request (www.login-server.com/adfs/ls/?SAMLRequest=xxx...), your application had totally forgotten about that request. In other word, it no longer kept the request ID somewhere and couldn't verify response.
The solution is to tell your users not to bookmark the www.login-server.com/adfs/ls/?SAMLRequest=xxx... link. Instead, they must bookmark a link in your application where it can generate a new request and send to ADFS.

symfony2 security - disable login path and show forbidden

i am trying to prevent redirect to login page when user is trying to access a page without token, i have single page app and i am only putting the ajax requests under firewall and when a user is doing ajax without token i want the ajax to return forbidden exception so i will be able to catch it in client side
currently the ajax returns "Found" since the request is being redirected to the login page
i haven't found a solution in cookbook so far i dont want to use api tokens, only send an exception instead of redirecting to login
You need to define an entry_point to your firewall in order for you to return unauthorized response. Information about entry points can be found in the documentation here. I will copy the paragraph in case of future requests here.
When the user is not authenticated at all (i.e. when the token storage has no token yet), the firewall's entry point will be called to "start" the authentication process. An entry point should implement AuthenticationEntryPointInterface, which has only one method: start(). This method receives the current Request object and the exception by which the exception listener was triggered. The method should return a Response object. This could be, for instance, the page containing the login form or, in the case of Basic HTTP authentication, a response with a WWW-Authenticate header, which will prompt the user to supply their username and password.
So in order for you to do that, you have to create a class that is going to be defined as a service.
It should look like this:
namespace MyBundle\Service;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
class CustomEntryPoint implements AuthenticationEntryPointInterface
{
public function start(Request $request, AuthenticationException $authException = null)
{
$response = new Response("", Response::HTTP_UNAUTHORIZED);
return $response;
}
}
And in your services.yml file
services:
service.entry_point:
class: MyBundle\Service\CustomEntryPoint
And finally pass the service id service.entry_point to your entry_point option in firewall section of security.yml file.
This should do the trick.

How to see the redirect status from an STS / IdP

I have searched (probed ,even) for an answer to this but haven't come up with anything useful so far. I'm pretty new to ADFS, STS's in general and WIF so please excuse any obvious ignorance or inappropriate use of terminology. ;)
I'm currently integrating a custom MVC3 app with an external IdP, via ADFS. The ADFS to IdP setup is all done and working.
Some parts of the site are accessible to anon users - in the web.config authentication mode has been set to none. The other parts are protected by having their controllers/action methods decorated by a custom System.Web.Mvc.AuthorizeAttribute.
All the usual modifications to the web.config for using the WsFederationAuthenticationModule have been made and it works 95%; the user can browse to the anon accessible parts of the site. When they try and hit the protected parts, the authorize attribute checks if they have some custom information from our IdP in the IClaimsPrincipals associated with the HttpContext.Current.User and then sets the ActionResult to 401 if not; The WsFederationAuthenticationModule kicks in and redirects them to the IdP's login page. When they enter their details, they're then successfully redirected with some FedAuth cookies and the authorization then passes.
The problem starts when they get to the IdP's login page. This particular IdP has a link to return you directly to our site (to the same page the original request was made to), with this SAML response embedded somewhere (this is according to their documentation)
urn:oasis:names: tc:SAML:2.0:status: AuthnFailed
At this point, they are now "Unauthorized" and all the user will see (at least in dev) is a 401 page. You have to kill the session or otherwise get rid of that cookie to start again.
What I need to do is intercept that redirect request from the IdP, and essentially check for that particular SAML status, because the user should then be redirected to one of the unauthorized areas as if nothing has happened. I've tried something like this in the global.asax:
protected void Application_Start()
{
// mvc stuff here....
// add handler to intercept handling creation of security tokens by WsFederationAuthnticationModule
FederatedAuthentication.ServiceConfigurationCreated += OnServiceConfigurationCreated;
}
void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
{
FederatedAuthentication
.WSFederationAuthenticationModule
.SessionSecurityTokenCreated += WSFederationAuthenticationModule_SecuityTokenCreated;
}
public void WSFederationAuthenticationModule_SecuityTokenCreated (Object sender, SessionSecurityTokenCreatedEventArgs args)
{
var token = args.SessionToken;
// do something with the session token here e.g. check for SAML status
}
.. but I cant see anything useful on that token; nothing to indicate a specific response status. The fact that there is a FedAuth cookie at all but no custom info from the Idp is a dead give away that the user has been there but somehow failed to authenticate, but in principle I want to be able to see that status. I might have to deal with timeouts at the IdP as well....
Maybe I'm doing this all wrong, or just plain old don't understand, but can somehow fill me in on how to determine those response statuses?
Phew. Thank you! :D
Ok, so I'm going to answer my own question.
The answer to whether I can get that custom status from my IdP is a no, at the moment. :(
But this is only because ADFS is not setup to capture it and pass it on. Apparently you need to do some custom coding for capturing information from the back channel that is opened between ADFS and the IdP.... well beyond the current scope of work.
As a work around for the moment:
If a request is made to the site and there is NO SAML token, its a new request by a user who has made no auth attempt at the Idp
If there is a SAML token but no ID from the IdP in the token (which is only present when they auth properly), then the user failed Auth for some reason
If there is a SAML token with the ID present, the user auth'd properly
Not great but acceptable. BTW, all credit goes to YMC in this SO post for the following code which lets you check for SAML tokens:
void WSFederationAuthenticationModule_SecurityTokenReceived(object sender, SecurityTokenReceivedEventArgs e)
{
var message = SignInResponseMessage.CreateFromFormPost(Request) as SignInResponseMessage;
var rstr = new WSFederationSerializer()
.CreateResponse(message,
new WSTrustSerializationContext(
SecurityTokenHandlerCollectionManager.CreateDefaultSecurityTokenHandlerCollectionManager()));
}
Pce!

Resources