I'm playing around with the grails 2 framework in addition with the spring-security-plugin.
I built a custom login form, which should be always visible on the main page.
Thus, the user should always be redirected to the main page. Regardless of whether an error occurs or not.
In the case of a successful login everything works very well, but in the case of an error the flash scope is lost during the redirect. So I can't display the reason for the failed authentication.
According to the documentation, only the parameter 'defaultFailureUrl' should be adjusted.
But this doesn't work as expected.
Are there any other parameters necessary to achieve this functionality?
My Config.groovy
// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.successHandler.defaultTargetUrl="/"
grails.plugin.springsecurity.successHandler.alwaysUseDefault=true
grails.plugin.springsecurity.failureHandler.defaultFailureUrl = '/'
grails.plugin.springsecurity.auth.loginFormUrl = '/'
grails.plugin.springsecurity.logout.postOnly = false // Logout through direct link
grails.plugin.springsecurity.userLookup.userDomainClassName = 'de.msg.login.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'de.msg.login.UserRole'
grails.plugin.springsecurity.authority.className = 'de.msg.login.Role'
I hope someone can figure out a solution ;)
As I understood you want to show the message on same login page after submit the login page.
Use this property probably it will work :
set this in config.groovy
failureHandler.useForward=false
See this link
Related
Ok, first question ever so be gentle. I've been struggling with this for about a week now and i am finally ready to accept defeat and ask for help.
Here's what is happening. I have an IdentityServer4 IDP, an API and an MVC Core Client. I am also interacting with 2 external OAuth2 IDPs provided by the business client.
My problem scenario is this:
The user logs in through my IDP(or potentially one of the external ones)
Once the user is in the Mvc Client they hit the back button on their browser
Which takes them back to the login page(whichever one they used)
They reenter the credentials(login again)
When redirected back(either to the MVC in the case of my IDP, or my IDP in the case of one of the external IDPs) i get RemoteFailure event with the message:correlation failed error
The problem seems, to me, to be the fact that you are trying to login when you are already logged in(or something). I've managed to deal with the case of logging in at my IDP, since the back button step takes the user to my Login action on the Controller(I then check if a user is authenticated and send them back to the MVC without showing them any page) but with the other two IDPs the back button does not hit any code in my IDP. Here are the config options for one of the OAuth2 external IDPs:
.AddOAuth(AppSettings.ExternalProvidersSettings.LoginProviderName, ExternalProviders.LoginLabel, o =>
{
o.ClientId = "clientId";
o.ClientSecret = "clientSecret";
o.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
o.CallbackPath = PathString.FromUriComponent(AppSettings.ExternalProvidersSettings.LoginCallbackPath);
o.AuthorizationEndpoint = AppSettings.ExternalProvidersSettings.LoginAuthorizationEndpoint;
o.TokenEndpoint = AppSettings.ExternalProvidersSettings.LoginTokenEndpoint;
o.Scope.Add("openid");
o.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
//stuff
},
OnRemoteFailure = async context =>
{
if (!HostingEnvironment.IsDevelopment())
{
context.Response.Redirect($"/home/error");
context.HandleResponse();
}
}
};
}
The other one is the same. Since the error is exactly the same regardless of the IDP used, i am guessing it is not something native to OIDC but to OAuth middleware and the code(config options) they share, so i am not going to show the OIDC config on the MVC client(unless you insist). Given how simple the repro steps are i thought i would find an answer and explanation to my problem pretty fast, but i was not able to. Maybe the fix is trivial and i am just blind. Regardless of the situation, i would apreciate help.
I could reproduce your issue.
When the user goes back to the login screen after successfully logging in,
it might well be that the query parameters in the URL of that page are no longer valid.
Don't think this is an issue specific to Identity Server.
You may read
https://github.com/IdentityServer/IdentityServer4/issues/1251
https://github.com/IdentityServer/IdentityServer4/issues/720
Not sure how to prevent this from happening though.
I have been trying to configure the oauth2 provider plugin in my grails application, but I am facing certain issues, and other than the plugin documentation, I didn't find any other sources that could help.
I have followed all the stepd mentioned in the doc, and made changes in Config.groovy
Now hitting localhost:8080/oauth/authorize?response_type=code&client_id=my-client&scope=read should redirect me to login page which it does.
After login however, I want authorization window to appear where user accepts or rejects granting authorization. I am however just getting a JSON result:
{"url":"http://localhost:8080/oauth/authorize?response_type=code&client_id=my-client&scope=read","success":true}
Why am I not getting an authorization prompt instead? What am I missing here?
Okay. So I have made some changes:
grails.plugin.springsecurity.filterChain.filterNames = [
'cookieSessionFilter',
'securityContextPersistenceFilter', 'statelessSecurityContextPersistenceFilter','logoutFilter',
'authenticationProcessingFilter','exceptionTranslationFilter', 'oauth2ProviderFilter', 'clientCredentialsTokenEndpointFilter',
'oauth2BasicAuthenticationFilter', 'securityContextHolderAwareRequestFilter',
'rememberMeAuthenticationFilter','anonymousAuthenticationFilter', 'oauth2ExceptionTranslationFilter', 'filterInvocationInterceptor'
]
grails.plugin.springsecurity.filterChain.chainMap = [
'/oauth/token': 'JOINED_FILTERS, -cookieSessionFilter, -oauth2ProviderFilter,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-exceptionTranslationFilter' ,
'/securedOAuth2Resources/**': 'JOINED_FILTERS,-cookieSessionFilter, -securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-oauth2BasicAuthenticationFilter,-exceptionTranslationFilter',
'/**': 'JOINED_FILTERS,-statelessSecurityContextPersistenceFilter,-oauth2ProviderFilter,-clientCredentialsTokenEndpointFilter,-oauth2BasicAuthenticationFilter,-oauth2ExceptionTranslationFilter'
]
Just proper ordering of filters seems to be solving the problem.
With this configuration I am able to generate the access_token.
1.
I have setup a CAS server up and running at port: 8443 url -> https://ekansh/cas.
I can see the login page and i am successfully able to login using mysql database user table credentials. and even logout and see status.
I created a demo grails app, installed spring security plugin and created user role mappings by s2-quickstart. and scaffolding domains.
I added the
compile ":spring-security-core:2.0-RC4"
compile ":spring-security-cas:2.0-RC1"
dependencies.
Added configurations in Config.grovy
grails.plugin.springsecurity.cas.active = true
grails.plugin.springsecurity.cas.loginUri = '/login'
grails.plugin.springsecurity.cas.sendRenew = false
grails.plugin.springsecurity.cas.serviceUrl = 'http://ekansh:8095/app1/j_spring_cas_security_check'
grails.plugin.springsecurity.cas.serverUrlEncoding = 'UTF-8'
grails.plugin.springsecurity.cas.key = 'grails-spring-security-cas'
grails.plugin.springsecurity.cas.artifactParameter = 'ticket'
grails.plugin.springsecurity.cas.serviceParameter = 'service'
grails.plugin.springsecurity.cas.filterProcessesUrl = '/j_spring_cas_security_check'
grails.plugin.springsecurity.cas.proxyCallbackUrl = 'http://ekansh:8095/app1/secure/receptor'
grails.plugin.springsecurity.cas.useSingleSignout = true
grails.plugin.springsecurity.cas.serverUrlPrefix = 'https://ekansh:8443/cas'
grails.plugin.springsecurity.cas.proxyCallbackUrl = 'http://ekansh:8095/app1/secure/receptor'
grails.plugin.springsecurity.cas.proxyReceptorUrl = '/secure/receptor'
grails.plugin.springsecurity.logout.afterLogoutUrl ='https://ekansh:8443/cas/logout?url=http://ekansh:8095/app1/'
grails.plugin.springsecurity.providerNames = ['casAuthenticationProvider']
Nw when i run this app, i get redirected to cas server page, i enter the credentials, it logs me into cas server, but it sends me to the spring security login page with message that
Sorry, we were not able to find a user with that username and password. And i am not even able to sign in to the application from this point.
What am i missing ? Why am i getting spring security login page.
I also found that when i comment line grails.plugin.springsecurity.providerNames = ['casAuthenticationProvider'], i am able to login to the system. I have not altered the casAuthenticationProvider.
Any help would be appriciated.
I found the answer to my question after a lot of research. Basically i did mess up with the configurations of the cas server.
The user was getting logged into the cas server but a ticket was not being generated for the same user, thus it was still sending a user not authenticated response back to the application and spring security, was redirecting to the login page.
I am using the following code in my logout button :
<a id="login-control-logout" href="${createLink(controller:'LicGenerator', action:'logout')}"><i class="icon-off"></i> Logout</a></li>
Inside my controller, I am using the following code :
def logout() {
request.getSession().invalidate()
response.setHeader("Cache-Control","no-cache,no-store,must-revalidate")
response.setHeader("Pragma","no-cache")
response.setDateHeader("Expires", 0)
redirect(uri:'/login.html')
}
It goes to login.html, but when I enter the username and password again, it doesn't log me back in and throws an error
type Status report
message /LicGenerator/j_security_check
description The requested resource (/LicGenerator/j_security_check) is not available.
When I refresh the browser, I got this error :
type Status report
message Invalid direct reference to form login page
description The request sent by the client was syntactically incorrect (Invalid direct reference to form login page).
Also, the back button takes me to page even though I added cache control to response.
Simply invalidating your session for spring security is probably not advisable. As there is a SecuritySession which also has cookies. It may be better to use whats provided by spring security already.
import grails.plugin.springsecurity.SpringSecurityUtils
redirect uri: SpringSecurityUtils.securityConfig.logout.filterProcessesUrl
Then you can configure your default login url via the config options for the spring security plugin
I have a web application that contains a REST api that is interacted with by the client application that lives at /. When a user session times out and the client js application makes a request to the REST api, that request will trigger a login event. Once the user logs in the user is then taken to the REST api endpoint which just displays a JSON response. I would like to hard wire the login page to always redirect to /.
Edit 1: I'm using spring-security-core plugin with the openid plugin as well and grails 2.0.4.
Edit 2: So I managed to get a solution working, however its a bit crude and I would like to know if there is a more elegant solution out there.
I created a simple filter in grails-app/conf/LoginRedirectFilters.groovy:
class RedirectLoginFilters {
def filters = {
redirectAfterLogin (uri: '/api/*') {
before = {
if (session["LOGGING_IN"])
redirect uri: "/"
}
after = {
if (session["LOGGING_IN"])
session["LOGGING_IN"] = false
}
}
}
}
And in my auth function inside of OpenIdController.groovy I added the session flag LOGGING_IN:
def auth = {
def config = SpringSecurityUtils.securityConfig
if (springSecurityService.isLoggedIn()) {
redirect uri: config.successHandler.defaultTargetUrl
return
}
session["LOGGING_IN"] = true
.
.
.
This is working properly by only checking if the LOGGING_IN flag is true when an api endpoint is called, and it also kills the flag after one request so it won't interfere with subsequent client api calls. I realize this is pretty convoluted, so if there is a better solution please let me know, thanks!
Why can't you use the same "springSecurityService.isLoggedIn()" inside your filter as well? I'm pretty sure that works as well.
I think I'm misunderstanding exactly what you want to achieve, but if you always want to redirect to '/' after a successful login, just set these properties in your Config.groovy:
grails.plugins.springsecurity.successHandler.alwaysUseDefault = true
grails.plugins.springsecurity.successHandler.defaultTargetUrl = "/"
If you want different behaviour to this, you'll have to flesh out your question.