Grails3 is used in spring security Shiro, but do not know how to use, the feeling is basically used spring security core.
My configuration is as follows:
package com.system
class Permission {
Person person
String permission
Permission(Person person, String permission) {
this.person = person
this.permission = permission
}
static constraints = {
authority nullable: true
permission unique: ['person', 'authority']
}
}
grails.plugin.springsecurity.userLookup.userDomainClassName =
'com.system.Person'
grails.plugin.springsecurity.userLookup.authorityJoinClassName =
'com.system.PersonAuthority'
grails.plugin.springsecurity.authority.className = 'com.system.Authority'
grails.plugin.springsecurity.shiro.active = true
grails.plugin.springsecurity.logout.postOnly = false
grails.plugin.springsecurity.shiro.permissionDomainClassName =
'com.system.Permission'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/', access: ['permitAll']],
[pattern: '/error', access: ['permitAll']],
[pattern: '/notFound', access: ['permitAll']],
[pattern: '/index', access: ['permitAll']],
[pattern: '/index.gsp', access: ['permitAll']],
[pattern: '/shutdown', access: ['permitAll']],
[pattern: '/assets/**', access: ['permitAll']],
[pattern: '/uploads/**', access: ['permitAll']],
[pattern: '/**/js/**', access: ['permitAll']],
[pattern: '/**/css/**', access: ['permitAll']],
[pattern: '/**/images/**', access: ['permitAll']],
[pattern: '/**/fonts/**', access: ['permitAll']],
[pattern: '/**/favicon.ico', access: ['permitAll']]
]
grails.plugin.springsecurity.filterChain.chainMap = [
[pattern: '/assets/**', filters: 'none'],
[pattern: '/**/js/**', filters: 'none'],
[pattern: '/**/css/**', filters: 'none'],
[pattern: '/**/images/**', filters: 'none'],
[pattern: '/**/fonts', filters: 'none'],
[pattern: '/**/favicon.ico', filters: 'none'],
[pattern: '/**', filters: 'JOINED_FILTERS']
]
Related
I am using grails spring-security-rest to generate the JWT token.
my config looks like below
grails.plugin.springsecurity.userLookup.userDomainClassName =
'com.kps.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName =
'com.kps.UserRole' grails.plugin.springsecurity.authority.className =
'com.kps.Role' grails.plugin.springsecurity.securityConfigType =
"InterceptUrlMap"
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/', access: ['permitAll']], [pattern:
'/error', access: ['permitAll']], [pattern: '/index',
access: ['permitAll']], [pattern: '/index.gsp', access:
['permitAll']], [pattern: '/shutdown', access: ['permitAll']],
[pattern: '/assets/', access: ['permitAll']], [pattern:
'//js/', access: ['permitAll']], [pattern: '//css/',
access: ['permitAll']], [pattern: '//images/', access:
['permitAll']], [pattern: '//favicon.ico', access: ['permitAll']],
[pattern: '/api/login', access: ['permitAll']] ]
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: '/**', filters:
'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'
],
//Traditional, stateful chain [ pattern: '/stateful/**',
filters:
'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
] ]
grails.plugin.springsecurity.rest.logout.endpointUrl = '/api/logout'
grails.plugin.springsecurity.rest.token.generation.jwt.issuer='ash'
grails.plugin.springsecurity.rest.token.generation.jwt.algorithm="HS256"
grails.plugin.springsecurity.rest.token.storage.jwt.secret="secret"
grails.plugin.springsecurity.rest.token.storage.jwt.useSignedJwt=true
grails.plugin.springsecurity.rest.token.storage.jwt.expiration=3600
rails.plugin.springsecurity.rest.token.generation.jwt.jweAlgorithm="RSA-OAEP"
grails.plugin.springsecurity.rest.token.generation.jwt.encryptionMethod="A128GCM"
The response I am getting
{
"username": "user1",
"roles": [
"ROLE_USER"
],
"token_type": "Bearer",
"access_token": "l755g5o1stj8f1capi9cibtq4e5lr63p"
}
token here is not a JWT Token. Can any one guide me on this
I'm having some trouble making a "refresh_token" request with Spring Security Rest in a Grails 3 application. I have an application with both a web front-end and some Rest endpoints, and everything else seems to be working fine. The web app behaves as expected and, when I make a login request via curl with
curl -i -X POST localhost:8080/api/login \
-H "Content-Type: application/json" \
-d '{"username":"johndoe", "password":"johndoepassword"}'
I get back the expected response (I have truncated the tokens):
{
"username":"johndoe",
"roles":["ROLE_USER"],
"token_type":"Bearer",
"access_token":"eyJhbGciOiJIUzI1NiJ9.xxxxxx",
"expires_in":3600,
"refresh_token":"eyJhbGciOiJIUzI1NiJ9.xxxx"
}
In the actual application, I can add the access_token to the header and authenticate with no problem for the duration of the session. However, I get a 403 when I hit the "refresh token" endpoint with
curl -i -X POST localhost:8080/oauth/access_token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token&refresh_token=eyJhbGciOiJIUzI1NiJ9.xxxx"
This all seems pretty straightforward in the docs, but I'm obviously doing something wrong. Here's what I think is the relevant portion of my config file:
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/error', access: ['permitAll']],
[pattern: '/login', access: ['permitAll']],
[pattern: '/login/**', access: ['permitAll']],
[pattern: '/oauth/**', access: ['permitAll']],
[pattern: '/user/register', access: ['permitAll']],
[pattern: '/user/register/**', access: ['permitAll']],
[pattern: '/user/submitRegistration', access: ['permitAll']],
[pattern: '/logoff', access: ['permitAll']],
[pattern: '/shutdown', access: ['permitAll']],
[pattern: '/assets/**', access: ['permitAll']],
[pattern: '/**/js/**', access: ['permitAll']],
[pattern: '/**/css/**', access: ['permitAll']],
[pattern: '/**/images/**', access: ['permitAll']],
[pattern: '/**/favicon.ico', access: ['permitAll']],
[pattern: '/surveyAdmin/**', access: ['ROLE_ADMIN']] ,
[pattern: '/**', access: ['ROLE_USER']]
]
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'
],
[
pattern: '/rest/**',
filters: 'restTokenValidationFilter,restExceptionTranslationFilter,filterInvocationInterceptor'
],
[pattern: '/**', filters: 'JOINED_FILTERS']
]
Can anyone suggest a way through here?
Thanks,
Alex
As so often happens, I found the answer shortly after posting the question. I'm using a custom user class that implements org.springframework.security.core.userdetails.UserDetails but does not extend org.springframework.security.core.userdetails.User. The plugin assumes the principal can be cast to a "User" object, which was causing the user lookup/token generation to fail. Either changing my custom class to extend User or overriding the refreshToken method in the plugin to accept my custom user class got things working.
I'm trying to enable CORS support in a Grails 3.1.12 app using this plugin: https://github.com/appcela/grails3-cors-interceptor
I followed the documentation and here is my security configuration in application.groovy:
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/', access: ['permitAll']],
[pattern: '/error', access: ['permitAll']],
[pattern: '/index', access: ['permitAll']],
[pattern: '/index.gsp', access: ['permitAll']],
[pattern: '/shutdown', access: ['permitAll']],
[pattern: '/assets/**', access: ['permitAll']],
[pattern: '/**/js/**', access: ['permitAll']],
[pattern: '/**/css/**', access: ['permitAll']],
[pattern: '/**/images/**', access: ['permitAll']],
[pattern: '/**/favicon.ico', access: ['permitAll']],
// EDIT: block all other URL access
[pattern: '/**', access: ['denyAll'], httpMethod: 'GET'],
[pattern: '/**', access: ['denyAll'], httpMethod: 'POST'],
[pattern: '/**', access: ['denyAll'], httpMethod: 'PUT'],
[pattern: '/**', access: ['denyAll'], httpMethod: 'DELETE']
]
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/login', filters: 'securityCorsFilter,restAuthenticationFilter'],
// see http://alvarosanchez.github.io/grails-angularjs-springsecurity-workshop/
// [pattern: '/**', filters: 'JOINED_FILTERS'],
[
pattern: '/api/**',
filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'
]
]
// EDIT: Optimistic approach (restrict access by URL only) to allow 'OPTIONS' access for CORS
grails.plugin.springsecurity.rejectIfNoRule = false
grails.plugin.springsecurity.fii.rejectPublicInvocations = false
My problem is that when I send an OPTIONS request to any of my /api/something endpoints without providing authorization headers, I get a 401 status and I don't understand why.
OK, I noticed one key difference with the sample project. My project uses RestfulController and the #Secured annotation at the controller level, and that was what was responsible for the 401 on OPTIONS. I overrode all the methods to protect them at the method level and now I don't get a 401 anymore.
You can try this solution (that worked for me, with grails 3.1.x):
CrosFilter.java:
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Priority;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Priority(Integer.MIN_VALUE)
public class CorsFilter extends OncePerRequestFilter {
public CorsFilter() { }
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain)
throws ServletException, IOException {
String origin = req.getHeader("Origin");
boolean options = "OPTIONS".equals(req.getMethod());
if (options) {
if (origin == null) return;
resp.addHeader("Access-Control-Allow-Headers", "origin, authorization, accept, content-type, x-requested-with");
resp.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
resp.addHeader("Access-Control-Max-Age", "3600");
}
resp.addHeader("Access-Control-Allow-Origin", origin == null || origin.equals("null") ? "*" : origin);
resp.addHeader("Access-Control-Allow-Credentials", "true");
if (!options) chain.doFilter(req, resp);
}
}
if you use a plugin profile:
src/main/groovy/pluginname/PluginNameGrailsPlugin.groovy:
Closure doWithSpring() {
{ ->
corsFilter(CorsFilter)
}
}
for web application profile:
grails-app/conf/spring/resources.groovy:
beans = {
corsFilter(CorsFilter)
}
I am using Grails 3.1.4 together with the Spring Security Rest Plugin 2.0.0.M2 for implementing a single page app with AngularJS.
Login and validation is working perfectly fine, but when I call logout I get a 404 error.
When debugging, I get an exception in the plugin RestLogoutFilter:
try {
log.debug "Trying to remove the token"
tokenStorageService.removeToken accessToken.accessToken
} catch (TokenNotFoundException tnfe) {
servletResponse.sendError HttpServletResponse.SC_NOT_FOUND, "Token not found"
}
Exception:
grails.plugin.springsecurity.rest.token.storage.TokenNotFoundException:
Token eyJh... cannot be removed as this is a stateless implementation
Calling
tokenStorageService.loadUserByToken(accessToken.accessToken)
works, so the token certainly is in the tokenStorage.
My Spring Security configuration is
grails.plugin.springsecurity.userLookup.userDomainClassName = 'myapp.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'myapp.UserRole'
grails.plugin.springsecurity.authority.className = 'myapp.Role'
grails.plugin.springsecurity.userLookup.usernamePropertyName='email'
grails.plugin.springsecurity.rest.login.usernamePropertyName='email'
grails.plugin.springsecurity.rest.token.storage.gorm.usernamePropertyName='email'
grails.plugin.springsecurity.rest.logout.endpointUrl = '/api/logout'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/', access: ['permitAll']],
[pattern: '/error', access: ['permitAll']],
[pattern: '/index', access: ['permitAll']],
[pattern: '/index.gsp', access: ['permitAll']],
[pattern: '/shutdown', access: ['permitAll']],
[pattern: '/assets/**', access: ['permitAll']],
[pattern: '/**/js/**', access: ['permitAll']],
[pattern: '/**/css/**', access: ['permitAll']],
[pattern: '/**/images/**', access: ['permitAll']],
[pattern: '/**/favicon.ico', access: ['permitAll']],
[pattern: '/api/logout', access: ['isAuthenticated()']]
]
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']
]
Is there an error in my config or any other thing wrong?
Found the answer minutes after asking the question.
The Spring Security Rest plugin documentation states:
Logout is not possible when using JWT tokens (the default strategy), as no state is kept in the server. If you still want to have logout, you can provide your own implementation by creating a subclass of JwtTokenStorageService and overriding the methods storeToken and removeToken.
Then, register your implementation in resources.groovy as tokenStorageService.
However, a more rational approach would be just to remove the token from the client (eg, browser's local storage) and let the tokens expire (they will expire anyway, unlike with other storages like Memcached or Redis where they get refreshed on every access).
So just deleting the token on the client is sufficient if one is using JWT for authorization.
I'm using Grails 3.1.4 with spring-security-rest plugin. Usually everthing works fine, but when one of our test users tries to fetch any data from a controller the server's cpu usage climbs up to 100% followed by a java.lang.outofmemory error.
I don't understand why the request work for other user accounts except his. Maybe it's about his name which contains an á character.
Update 8.4.16
It's not user account specific! But we noticed that this error only occurs for our client application on iOS 9.3 and later.
Debugging this error is kind of annoying and I don't have a clue how to resolve this issue.
Is there anyone who might provide a hint?
2016-03-26 20:42:20,476 ERROR http-bio-8443-exec-120 org.springframework.boot.context.web.ErrorPageFilter - Forwarding to error page from request [/users/2] due to exception [GC overhead limit exceeded]
java.lang.OutOfMemoryError: GC overhead limit exceeded
at grails.views.ResolvableGroovyTemplateEngine.resolveTemplate(ResolvableGroovyTemplateEngine.groovy:297)
at grails.views.mvc.GenericGroovyTemplateView.renderMergedOutputModel(GenericGroovyTemplateView.groovy:52)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1243)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1027)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:971)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:860)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at javax.servlet.FilterChain$doFilter.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at javax.servlet.FilterChain$doFilter$0.call(Unknown Source)
at grails.plugin.springsecurity.rest.RestAuthenticationFilter.doFilter(RestAuthenticationFilter.groovy:143)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at javax.servlet.FilterChain$doFilter.call(Unknown Source)
at grails.plugin.springsecurity.rest.RestLogoutFilter.doFilter(RestLogoutFilter.groovy:80)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at javax.servlet.FilterChain$doFilter.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
UserController.groovy
#Secured('ROLE_ADMIN')
class UserController extends RestfulController {
static responseFormats = ['json', 'xml']
UserController() {
super(User)
}
SpringSecurityService springSecurityService
#Secured('ROLE_USER')
def show() {
def authenticatedUser = springSecurityService.currentUser
User user = User.findById(params.long('id'))
if (user == null) {
render(message: 'User not found', status: 404)
} else if (user != authenticatedUser){
render(message: 'not authorized', status: 401)
} else if (user == authenticatedUser){
respond user
} else {
render status: 404
}
}
}
build.gradle
dependencies {
...
compile "org.grails.plugins:spring-security-rest:2.0.0.M2"
...
}
application.groovy
grails.plugin.springsecurity.filterChain.chainMap = [
//Stateless chain
[
pattern: '/**',
filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'
],
//Traditional, stateful chain
[
pattern: '/stateful/**',
filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
]
]
// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'net.connactivities.api.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'net.connactivities.api.UserRole'
grails.plugin.springsecurity.authority.className = 'net.connactivities.api.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
[pattern: '/', access: ['permitAll']],
[pattern: '/error', access: ['permitAll']],
[pattern: '/index', access: ['permitAll']],
[pattern: '/index.gsp', access: ['permitAll']],
[pattern: '/shutdown', access: ['permitAll']],
[pattern: '/assets/**', access: ['permitAll']],
[pattern: '/**/js/**', access: ['permitAll']],
[pattern: '/**/css/**', access: ['permitAll']],
[pattern: '/**/images/**', access: ['permitAll']],
[pattern: '/**/favicon.ico', access: ['permitAll']]
]
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: '/**', filters: 'JOINED_FILTERS']
]
RequestHandler.swift
...
let session = NSURLSession()
func performHTTPRequest(url: String, method: String, withParameters params: [String:AnyObject]?, useAuth: Bool = true, andCompletionBlock completionBlock: (success:Bool, data: NSData?)-> ()) {
let myURL = NSURL(string: url)
let request = NSMutableURLRequest(URL:myURL!)
// HTTP Method
request.HTTPMethod = method
// Include Header options
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
do {
if params != nil {
let body = try NSJSONSerialization.dataWithJSONObject(params!, options: .PrettyPrinted)
request.HTTPBody = body
}
} catch _ {
// Error handling
return
}
if useAuth {
if let auth = authorization() {
request.setValue("Bearer " + auth, forHTTPHeaderField: "Authorization")
}
}
let task = session.dataTaskWithRequest(request) {
data, response, error in
if error != nil {
// Error handling
return
}
let statusCode = (response as! NSHTTPURLResponse).statusCode
if statusCode.isNotAcceptedHTTPCode() {
// HTTP Error
}
else {
if data?.length != 0 {
// OK
}
else {
// Empty data
}
}
}
task.resume()
}
...