switch user feature throwing 404 page not found in grails 4.0.10? - grails

I am facing a really strange issue. The switch user feature is throwing 404 page not found error on our main application but it works in a new hello world app.
First of all i am using Grails 4.0.10 and spring security compile 'org.grails.plugins:spring-security-core:4.0.3'
the switch user form looks like this
<form action='${request.contextPath}/login/impersonate' method='POST'>
<input type="hidden" name="username" value="${user.email}"/>
<input type="hidden" name="${grailsApplication.config.grails.plugins.springsecurity.successHandler.targetUrlParameter}" value="/user/index"/>
<input type='submit' value="${message(code: 'user.button.switch.user')}" class="button"/>
</form>
the error thrown is
2022-08-31 00:24:20.851 WARN --- [nio-8443-exec-4] o.s.web.servlet.PageNotFound : No mapping for POST /roadrace/login/impersonate
the strange thing is i have implemented a simple switch user in a new hello world app following tutorial from https://grails.github.io/grails-spring-security-core/4.0.x/index.html#switchUser
it works in the hello world app but not in my main application. i have double checked all the configuration are in place
here are the relevant configuration
in application.groovy i have
grails.plugin.springsecurity.useSwitchUserFilter = true
grails.plugin.springsecurity.interceptUrlMap = [
[pattern: '/login/impersonate', access: ['ROLE_ADMIN', 'IS_AUTHENTICATED_FULLY']]
]
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
//'/public/**': 'ANY_CHANNEL',
[pattern: '/homePage/**', access: 'ANY_CHANNEL'],
[pattern: '/race/search*', access: 'ANY_CHANNEL'],
[pattern: '/images/**', access: 'ANY_CHANNEL'],
[pattern: '/uploads/**', access: 'ANY_CHANNEL'],
[pattern: '/css/**', access: 'ANY_CHANNEL'],
[pattern: '/js/**', access: 'ANY_CHANNEL'],
[pattern:'/static/**' , access: 'ANY_CHANNEL'],
[pattern: '/error/**', access: 'ANY_CHANNEL'],
[pattern: '/grails**', access: 'ANY_CHANNEL'],
[pattern:'/grails/**' , access:'ANY_CHANNEL' ],
[pattern: '/login/impersonate', access: ['ROLE_ADMIN', 'IS_AUTHENTICATED_FULLY']],
[pattern: '/logout/index', access: 'ANY_CHANNEL'],
[pattern: '/*', access: 'ANY_CHANNEL'],
[pattern: '/*/**', access: 'REQUIRES_SECURE_CHANNEL']
]
these are the minimal configuration to make switch user feature work.
what could be preventing the switch user feature to work or what could cause /login/impersonate to be not found?
I am also sharing the hello world app i created to test switch user
https://github.com/sanjaygir/switchuserhelloworld
if you run this grails 4 app and go to http://localhost:8080/secure/index there are two users with username me and me2 and the password is password. You can login as me with password password then in the switch user box you can type me2 and click switch. if you go again at http://localhost:8080/secure/index you can see it switched to me2.
i have used all the same configuration from this hello world app in my main app. it works in hello world app but it doesnt work in main app i.e it is throwing 404 when posting to /login/impersonate.
I appreciate any guidance to this strange issue? Thanks!

Related

Grails OAuth provider 404 on /token

Hi I am trying to setup an OAuth provider using this documentation from grails: Grails Documentation
I have done all the steps but when I try to do a request in postman I always got a 404 not found. I have tried many configs and I also tried some different filterChain.chainMap
I also have a MobileController that works fine that I can access in the project. I have tried to copy and paste the filterchain filters to make it the same as on /mobile/ But it still gave me a 404, I have ran the init script (s2-init-oauth2-provider) to make the domain classes
Here is my code that matters for the OAuth provider:
grails-app/conf/application.groovy:
List<String> url_public = [
'/mobile/**',
'/oauth/token'
]
grails.plugin.springsecurity.filterChain.chainMap = [
[pattern: '/oauth/token', filters: 'JOINED_FILTERS,-oauth2ProviderFilter,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-exceptionTranslationFilter'],
[pattern: '/mobile/**', filters: 'JOINED_FILTERS, -securityContextPersistenceFilter, -logoutFilter, -authenticationProcessingFilter, -rememberMeAuthenticationFilter, -oauth2BasicAuthenticationFilter, -exceptionTranslationFilter'],
[pattern: '/**', filters: 'JOINED_FILTERS, -basicAuthenticationFilter, -basicExceptionTranslationFilter, -statelessSecurityContextPersistenceFilter, -oauth2ProviderFilter, -clientCredentialsTokenEndpointFilter, -oauth2BasicAuthenticationFilter, -oauth2ExceptionTranslationFilter'],
]
grails.plugin.springsecurity.oauthProvider.clientLookup.className = 'com.app.oauth.OAuthClient'
grails.plugin.springsecurity.oauthProvider.authorizationCodeLookup.className = 'com.app.oauth.AuthorizationCode'
grails.plugin.springsecurity.oauthProvider.accessTokenLookup.className = 'com.app.oauth.AccessToken'
grails.plugin.springsecurity.oauthProvider.refreshTokenLookup.className = 'com.app.oauth.RefreshToken'
grails-app/init/Bootstrap.groovy:
new OAuthClient(
clientId: 'client_id',
authorizedGrantTypes: ['authorization_code', 'refresh_token', 'implicit', 'password', 'client_credentials'],
authorities: ['ROLE_client'],
scopes: ['read', 'write'],
).save(flush: true)
println "End bootstrap.init "
The fix was that I had to remove the url from the url_public list.
List<String> url_public = [
'/mobile/**'
]

How to get Session in UserDetailsService with Grails 3?

I've got a Grails 2.5 application that i'm trying to upgrade to 3.3 using Spring Security Core plugin (3.2.0.M1) with the preauth setup using Siteminder. In my UserDetailsService I get the Session like this:
UserDetails loadUserByUsername(String userId, boolean loadRoles) throws UsernameNotFoundException, DataAccessException {
org.grails.web.util.WebUtils.retrieveGrailsWebRequest().getCurrentRequest().getSession()
I need to get more than the single header passed into the app and when running the app locally this works as expected but when running through a war, on weblogic 12.2.1, I get this error:
No thread-bound request found: Are you referring to request attributes outside of an
actual web request, or processing a request outside of the originally receiving thread?
If you are actually operating within a web request and still receive this message, your code
is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use
RequestContextListener or RequestContextFilter to expose the current request.
I have also tried:
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
but ran into a NPE on getRequest(). When running in Grails 2.5 with Spring Sec Core plugin 2.0-RC6, the RequestContextHolder way worked correctly. Is there a different way to grab the headers maybe? Or is it possible some property I pulled over from my previous Config.groovy file into application.groovy may have caused a problem?
resources.groovy:
beans = {
userDetailsService(com.myapp.security.MyUserDetailsService)
userDetailsServiceWrapper(org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper) {
userDetailsService = ref('userDetailsService')
}
preauthAuthProvider(org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider) {
preAuthenticatedUserDetailsService = ref('userDetailsServiceWrapper')
}
requestHeaderAuthenticationFilter(org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter){
principalRequestHeader='smauthid'
checkForPrincipalChanges = false
invalidateSessionOnPrincipalChange = false
continueFilterChainOnUnsuccessfulAuthentication = true
authenticationManager = ref('authenticationManager')
}
}
Bootstrap.groovy
SpringSecurityUtils.clientRegisterFilter('requestHeaderAuthenticationFilter', SecurityFilterPosition.PRE_AUTH_FILTER)
application.groovy
grails.plugin.springsecurity.filterChain.chainMap = [
[pattern: '/assets/**', filters: 'none'],
[pattern: '/**/js/**', filters: 'none'],
[pattern: '/**/css/**', filters: 'none'],
[pattern: '/**/images/**', filters: 'none'],
[pattern: '/**/favicon.ico', filters: 'none'],
[pattern: '/index/nouser', filters: 'none'],
[pattern: '/nouser', filters: 'none'],
[pattern: '/**', filters: 'JOINED_FILTERS']
]
grails.plugin.springsecurity.providerNames = ['preauthAuthProvider']
I am not sure if there is any difference in getting Session in UserDetailsService but I get my session by:
session["task"]=object
You can read more about session right here: Grails 3 latest Session documentation.
EDIT 1
def show(Project project) {
respond project
def object = project //params of the Task "task"
session["task"]=object
}

URL access denied in grails spring-security

Iam using spring-security-core 3.1.1 in my grails 3.2.7 application. I just want to access my projectconfiguration.gsp, for this I added the following mapping in UrlMapping
"/confproject"(view: '/project/projectconfiguration')
But it is showing as You are not authorized to access this page
I know this is happened because of i did not specify any access rules for this URL. So i added the following line in the application.groovy
grails.plugin.springsecurity.controllerAnnotations.staticRules = [ [pattern: '/confproject', access: ['ROLE_ADMIN']] ]
But still iam facing the unauthorized access message.
Why the above access rule is note working?
I know that if I access the GSP through a controller and give the #Secured annotation to that controller will work fine.
But is that the only way?
Note: I don't want to use the interceptUrlMap method.
This is working for me.
UrlMappings.groovy
"/newsletter"(view: "/pages/newsletter")
application.groovy
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
...
[pattern: '/pages/**', access: ['permitAll']],
...
]

Grails 3.2.9 with Spring Security plugin 3.1.2 got "too many redirects" with default configuration

Created a new app, added compile 'org.grails.plugins:spring-security-core:3.1.2' and did:
grails s2-quickstart com.cabolabs.security User Role RequestMap
Then grails run-app.
Trying to access the /dbconsole, redirects to /login/auth
/login/auth got "localhost redirected you too many times." ERR_TOO_MANY_REDIRECTS
Is this the expected behavior or a bug form the plugin?
The doc, on the install and configuration section, doesn't mention anything about this https://grails-plugins.github.io/grails-spring-security-core/v3/#configuration
UPDATE
Found on the documentation, section 5.3 (https://grails-plugins.github.io/grails-spring-security-core/v3/) the initial RequestMap that should be added.
for (String url in [
'/', '/error', '/index', '/index.gsp', '/**/favicon.ico', '/shutdown',
'/**/js/**', '/**/css/**', '/**/images/**',
'/login', '/login.*', '/login/*',
'/logout', '/logout.*', '/logout/*']) {
new Requestmap(url: url, configAttribute: 'permitAll').save()
}
Used that in the Bootstrap.groovy, and still got the "too many redirects".
Also, can't view the /dbconsole to check the database because it's blocked by the plugin.
The solution proposed on GitHub and I tested it to work is to call clearCachedRequestmaps after creating the request map instances.
for (String url in [
'/', '/error', '/index', '/index.gsp', '/**/favicon.ico', '/shutdown',
'/**/js/**', '/**/css/**', '/**/images/**',
'/login', '/login.*', '/login/*',
'/logout', '/logout.*', '/logout/*']) {
new RequestMap(url: url, configAttribute: 'permitAll').save()
}
springSecurityService.clearCachedRequestmaps()
Little late but I just ran into the same issue. The way I fixed it was to add the following element to the chainMap:
[pattern: "/login/**", filters:"none"]
The reason why this worked is because spring was trying to get you to login before accessing the login page, which obviously wont work. The line above tells spring to allow traffic to the login endpoint without logging in first (since you can't).

Grails Spring Security plugin: Getting 302 for Ajax Request for timedout Session

We are using Spring Security plugin version 1.2.7.3 with Grails 2.2.1.
In my Config.groovy, I do:
grails.plugins.springsecurity.auth.ajaxLoginFormUrl = "/mylogin/authAjax"
thinking that, when there is an Ajax request, Spring Security will invoke authAjax() in MyloginController if the User's HttpSession has timed out.
As per doc, I ensure that the header X-Requested-With with value XMLHttpRequest is in the Ajax request so the plugin knows it is an Ajax request.
My expectation is authAjax() will be invoked and I can make that return a 401, so the UI knows it needs to pop up another login screen.
However, instead of the authAjax() getting invoked, a 302 is returned to the UI with the location field set to http://localhost:8080/MyApplication/mycontroller/authAjax
This means I'll have to put in something very hackey on my UI, check for a 302 and check the location field and then make the User re-login. I would much prefer to have a 401 returned.
Any ideas what I am doing wrong?
Thanks a million.
If anyone else has this issue, I found it was simply down to the chainMap rules.
I have my REST api sitting under the '/api/' url so my chainMap looks like this:
grails.plugin.springsecurity.filterChain.chainMap = [
[pattern: '/assets/**', filters: 'none'],
[pattern: '/**/js/**', filters: 'none'],
[pattern: '/**/css/**', filters: 'none'],
[pattern: '/**/images/**', filters: 'none'],
[pattern: '/**/favicon.ico', filters: 'none'],
[pattern: '/api/**', filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'], // Stateless API
[pattern: '/**', filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'] // Traditional, session based accesses.
]
The last 2 lines are the important bit; '/api/**' is secured by the Spring Security REST plugin which is a stateless connection (i.e. each request carries the authentication token). The '/**' rule covers everything else which requires a stateful session (the non-REST activity).
The stateless REST request will return 402 if the token has expired or is invalid in any way and the stateful non-rest will return 302 and send your browser round a loop.
Get those rules in the right order and you should be fine.

Resources