Code Monkey home page Code Monkey logo

grails-spring-security-rest's Introduction

Spring Security REST for Grails

Build Status Latest version Known Vulnerabilities

Grails plugin to implement a stateless, token-based, RESTful authentication using Spring Security. Sponsored and supported by Object Computing Inc.

Documentation:

Companies using this plugin

Are you using this plugin and want to be listed here? Include your company yourself.

Support

NOTE: if you have questions or issues, enable debug logging, and include the output in your request.

Contributors

License

This software is licensed under the terms of the Apache License, Version 2.0

grails-spring-security-rest's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

grails-spring-security-rest's Issues

Error Obtaining Dependecies

Hello

I am having an issue with the plugin which seems to have been introduced overnight (it was working fine in a number of projects yesterday). Anything changed? Thank you for any help ( I am using Grails 2.3.6 and JDK jdk1.7.0_51)

This is the error:

Error |
Resolve error obtaining dependencies: Could not find artifact org.pac4j:pac4j-oauth:jar:1.5.0-SNAPSHOT in grailsCentral (http://repo.grails.org/grails/plugins) (Use --stacktrace to see the full trace)
Error |
Could not find artifact org.pac4j:pac4j-oauth:jar:1.5.0-SNAPSHOT in grailsCentral (http://repo.grails.org/grails/plugins)
|Run 'grails dependency-report' for further information.

My BuildConfig

grails.project.dependency.resolution = {
mavenRepo "http://repo.spring.io/milestone/"
mavenRepo 'https://oss.sonatype.org/content/repositories/snapshots'

}
plugins {
compile ":spring-security-core:2.0-RC2"
compile ":spring-security-rest:1.3.0.RC2", {
excludes 'spring-security-core', 'cors'
}

Make plugin compatible with spring security core 1.2.7.3

I'd like to try the rest plugin in my applications but they all depend on spring security core 1.2.7.3. I pulled the source and I tried to build it agains the old library adjusting the imported classes, but I think there are other changes that need a deeper approach in order to make the plugin work, such as new classes defined in spring security 3.2.0.
As an example, see SimpleGrantedAuthority class imported in OauthService.groovy.
I'm not a Spring security expert, so I apologize in advance if the task was trivial and I couldn't do it by myself.

Sample implementation on the plugin

While the documentation goes into detail to explain the configuration of the plugin, there is nothing to show how we could have single page application use this. Therefore, could we put out out a test file (html / curl) with a code representation of the Authentication sequence present in the plugin documentation.

A sample implementation could help in not only getting a running start using this, but also have some good practices which is very much needed in such implementations.

Add support to delegate authentication to OAuth providers

Motivation

This plugin is meant to be used in applications serving a REST API's to pure Javascript clients. The main authentication flow of this plugin is to allow you to authenticate your users against any Spring Security-compatible user directory (like a DB or an LDAP server).

However, there might be situations where you want to delegate the authentication against a third-party provider, like Google or Facebook. Unfortunately, your pure Javascript front-end application cannot request the providers directly using OAuth, because then the access keys will be made public.

So is this plugin's responsibility to provide endpoints so your Grails backend acts as a proxy for your front-end client.

Solution

The flow will be like the following:

oauth

  1. The client application requests and endpoint that requires authentication, so the server responds with a 401 response (*).
  2. The client redirects the user to the login form (*).
  3. This time, instead of using username and password, the user clicks on "Login with Google" button.
  4. Browser navigates to a Grails URL. Grails will generate a Google Login URL, giving Google a Grails callback URL.
  5. Browser navigates to Google Login. User logs in, and Google redirects the browser to the Grails callback URL.
  6. Browser navigates to that Grails callback URL. Then, Grails will use OAuth to fetch user information (like email) from Google. Based on that, will generate a REST API token and fetch and store principal information. The response from Grails will be a front-end URL where the token is a parameter.
  7. The browser will navigate to that URL, and the Javascript logic will read the token from the URL and store it locally.
  8. The client sends again a request to the protected resource, passing the token as an HTTP header (*).

The steps flagged with (*) remain unchanged from the normal flow.

can't log in using form encoding; "anonymous" user seen

I have a grails app where spring security works properly. I added spring-security-rest with the following configuration:

BuildConfig.groovy:

plugins {
    compile ":spring-security-rest:1.2.4"

Config.groovy:

grails.plugin.springsecurity.rest.login.usernameParameter = "username"
grails.plugin.springsecurity.rest.login.passwordParameter = "password"

The login.gsp has <input name="username"> and <input name="password">. However, the username in the logs indicates the user is "anonymous", which (to me) implies it isn't picking up the form params. I'm stuck- I don't know how to debug further on this.

Here's the logging from a login attempt.

2014-02-17 17:30:12,801 [http-bio-8080-exec-6] DEBUG util.AntPathRequestMatcher  - Request '/j_spring_security_check' matched by universal pattern '/**'
2014-02-17 17:30:12,870 [http-bio-8080-exec-6] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 1 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2014-02-17 17:30:12,870 [http-bio-8080-exec-6] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 2 of 10 in additional filter chain; firing Filter: 'RestLogoutFilter'
2014-02-17 17:30:12,892 [http-bio-8080-exec-6] DEBUG rest.RestLogoutFilter  - Actual URI is /j_spring_security_check; endpoint URL is /logout
2014-02-17 17:30:12,894 [http-bio-8080-exec-6] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 3 of 10 in additional filter chain; firing Filter: 'MutableLogoutFilter'
2014-02-17 17:30:12,894 [http-bio-8080-exec-6] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 4 of 10 in additional filter chain; firing Filter: 'RestAuthenticationFilter'
2014-02-17 17:30:12,895 [http-bio-8080-exec-6] DEBUG rest.RestAuthenticationFilter  - Actual URI is /j_spring_security_check; endpoint URL is /login
2014-02-17 17:30:12,895 [http-bio-8080-exec-6] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 5 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2014-02-17 17:30:12,895 [http-bio-8080-exec-6] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 6 of 10 in additional filter chain; firing Filter: 'GrailsRememberMeAuthenticationFilter'
2014-02-17 17:30:12,896 [http-bio-8080-exec-6] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 7 of 10 in additional filter chain; firing Filter: 'GrailsAnonymousAuthenticationFilter'
2014-02-17 17:30:12,897 [http-bio-8080-exec-6] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 8 of 10 in additional filter chain; firing Filter: 'RestTokenValidationFilter'
2014-02-17 17:30:12,897 [http-bio-8080-exec-6] DEBUG rest.RestTokenValidationFilter  - Looking for a token value in the header 'X-Auth-Token'
2014-02-17 17:30:12,899 [http-bio-8080-exec-6] DEBUG rest.RestTokenValidationFilter  - Token not found
2014-02-17 17:30:12,899 [http-bio-8080-exec-6] DEBUG rest.RestTokenValidationFilter  - Actual URI is /j_spring_security_check; validate endpoint URL is /validate
2014-02-17 17:30:12,899 [http-bio-8080-exec-6] DEBUG rest.RestTokenValidationFilter  - Continuing the filter chain
2014-02-17 17:30:12,900 [http-bio-8080-exec-6] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 9 of 10 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2014-02-17 17:30:12,901 [http-bio-8080-exec-6] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 10 of 10 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2014-02-17 17:30:12,967 [http-bio-8080-exec-6] DEBUG intercept.FilterSecurityInterceptor  - Secure object: FilterInvocation: URL: /j_spring_security_check; Attributes: [_DENY_]
2014-02-17 17:30:12,968 [http-bio-8080-exec-6] DEBUG intercept.FilterSecurityInterceptor  - Previously Authenticated: grails.plugin.springsecurity.authentication.GrailsAnonymousAuthenticationToken@dc4d198: Principal: org.springframework.security.core.userdetails.User@dc730200: Username: __grails.anonymous.user__; Password: [PROTECTED]; Enabled: false; AccountNonExpired: false; credentialsNonExpired: false; AccountNonLocked: false; Granted Authorities: ROLE_ANONYMOUS; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: 10.0.2.2; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2014-02-17 17:30:12,977 [http-bio-8080-exec-6] DEBUG hierarchicalroles.RoleHierarchyImpl  - getReachableGrantedAuthorities() - From the roles [ROLE_ANONYMOUS] one can reach [ROLE_ANONYMOUS] in zero or more steps.
2014-02-17 17:30:14,212 [http-bio-8080-exec-6] DEBUG access.ExceptionTranslationFilter  - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
    at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.decide(AuthenticatedVetoableDecisionManager.java:47)
    at com.odobo.grails.plugin.springsecurity.rest.RestTokenValidationFilter.processFilterChain(RestTokenValidationFilter.groovy:88)
    at com.odobo.grails.plugin.springsecurity.rest.RestTokenValidationFilter.doFilter(RestTokenValidationFilter.groovy:68)
    at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53)
    at com.odobo.grails.plugin.springsecurity.rest.RestAuthenticationFilter.doFilter(RestAuthenticationFilter.groovy:108)
    at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82)
    at com.odobo.grails.plugin.springsecurity.rest.RestLogoutFilter.doFilter(RestLogoutFilter.groovy:66)
    at com.brandseye.cors.CorsFilter.doFilter(CorsFilter.java:82)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)
2014-02-17 17:30:14,220 [http-bio-8080-exec-6] DEBUG access.ExceptionTranslationFilter  - Calling Authentication entry point.
2014-02-17 17:30:14,228 [http-bio-8080-exec-6] DEBUG authentication.Http403ForbiddenEntryPoint  - Pre-authenticated entry point called. Rejecting access
2014-02-17 17:30:14,232 [http-bio-8080-exec-6] DEBUG context.SecurityContextPersistenceFilter  - SecurityContextHolder now cleared, as request processing completed

Note I haven't tried authenticating with JSON yet.

Generalize TokenStorageService.storeToken

Now the plugin is storing a org.springframework.security.core.userdetails.UserDetails object, but maybe some applications will want to store something different, like a JSON string.

The interface should allow any Object to be stored.

Fully qualified domain class name required to store Token using GORM

Based on the documentation about GORM Token Storage, the domain class has to be mentioned as a fully qualified class instead of just the name of the class.

grails.plugin.springsecurity.rest.token.storage.gorm.tokenDomainClassName = 
    'AuthenticationToken'

The above config setting will fail to store the token because of this implementation in GromTokenStorageService.groovy

grailsApplication.getClassForName(tokenClassName) expects that the class name provided is a fully qualified name (should include package as well). In that case the config should look like (say for example package com.example.auth for domain class AuthenticationToken ):

grails.plugin.springsecurity.rest.token.storage.gorm.tokenDomainClassName = 
    'com.example.auth.AuthenticationToken'

If we want to provide the flexibility of providing only the class name and not the fully qualified package name in config then the logic in GormTokenStorageService has to change as below:

def dc = grailsApplication.domainClasses?.find { it.clazz.simpleName == tokenClassName }?.clazz

here and here

Same plugin without grails

I'm searching for the same solution you have described but without grails with a pure spring solution ? any advice ?

/login/auth not being redirected to on non-restful controller/action requests

Hi Alvaro!

First of all I LOVE the plugin - thank you so much for creating it! My only "issue" with it is that the plugin seems to short-circuit Spring Security's default behavior of redirecting to /login/auth when browsing to a secured controller/action via a browser - it just comes back 403, obviously from the grails.plugin.springsecurity.rest.login.failureStatusCode configuration option. How can I get your WONDERFUL plugin to play more nicely in an environment with RESTful API(s) and traditional secured controllers/actions?

Edit: I see this mentioned in #31, but I am actually not quite sure how to do what you suggested as a work-around (I am relatively new to Grails and Java development, in general)

I am using Grails 2.3.7 with Spring Core 2.0 and version 1.3.1 of your plugin, if it helps.

Thanks again for the plugin!

:)

memcached enabled but not being used

TLDR version: memcached connects but never gets written to.

I'm running 1.3.0.RC3.

I'm using the following relevant configuration:

    debug  'com.odobo',
            'grails.app.controllers.com.odobo',
            'grails.app.services.com.odobo',
            'com.odobo',
            'org.pac4j',
            'org.springframework.security',
             'com.odobo.grails.plugin.springsecurity.rest.token.storage.MemcachedTokenStorageService',
            'net.spy.memcached'

grails.plugin.springsecurity.rest.token.storage.useMemcached = true
grails.plugin.springsecurity.rest.login.usernameParameter = "j_username"
grails.plugin.springsecurity.rest.login.passwordParameter = "j_password"

I can see the memcached connection being opened on startup- here's a snippet:

2014-02-19 19:47:23,331 [localhost-startStop-1] INFO  memcached.MemcachedConnection  - Added {QA sa=localhost/127.0.0.1:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
...
2014-02-19 19:47:26,368 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11211}] INFO  memcached.MemcachedConnection  - Connection state changed for sun.nio.ch.SelectionKeyImpl@7a838285
2014-02-19 19:47:26,385 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11211}] DEBUG binary.BinaryMemcachedNodeImpl  - Setting interested opts to 0
2014-02-19 19:47:26,398 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11211}] DEBUG memcached.MemcachedConnection  - Selecting with delay of 0ms

Since I'm running memcached on my dev box with -vvvv, I can see the connection being created too:

<30 new auto-negotiating client connection

Here's the filter chain that is created on startup:

2014-02-19 19:48:52,991 [localhost-startStop-1] INFO  web.DefaultSecurityFilterChain  - Creating filter chain: Ant [pattern='/**'], [org.springframework.security.web.context.SecurityContextPersistenceFilter@d47b54f, com.odobo.grails.plugin.springsecurity.rest.RestLogoutFilter@5ed05c58, grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter@415ec609, grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter@351b9a66, com.odobo.grails.plugin.springsecurity.rest.RestAuthenticationFilter@2735b9c7, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@3837cbed, grails.plugin.springsecurity.web.filter.GrailsRememberMeAuthenticationFilter@572d5170, grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter@603dbcc6, com.odobo.grails.plugin.springsecurity.rest.RestTokenValidationFilter@75349c86, org.springframework.security.web.access.ExceptionTranslationFilter@51105d87, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@96c73a5]

Finally, login is successful but does NOT contact memcached in any way.

2014-02-19 20:33:41,163 [http-bio-8080-exec-3] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2014-02-19 20:33:41,163 [http-bio-8080-exec-3] DEBUG context.HttpSessionSecurityContextRepository  - No HttpSession currently exists
2014-02-19 20:33:41,163 [http-bio-8080-exec-3] DEBUG context.HttpSessionSecurityContextRepository  - No SecurityContext was available from the HttpSession: null. A new one will be created.
2014-02-19 20:33:41,163 [http-bio-8080-exec-3] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 2 of 11 in additional filter chain; firing Filter: 'RestLogoutFilter'
2014-02-19 20:33:41,174 [http-bio-8080-exec-3] DEBUG rest.RestLogoutFilter  - Actual URI is /j_spring_security_check; endpoint URL is /api/logout
2014-02-19 20:33:41,178 [http-bio-8080-exec-3] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 3 of 11 in additional filter chain; firing Filter: 'MutableLogoutFilter'
2014-02-19 20:33:41,178 [http-bio-8080-exec-3] DEBUG web.FilterChainProxy  - /j_spring_security_check at position 4 of 11 in additional filter chain; firing Filter: 'RequestHolderAuthenticationFilter'
2014-02-19 20:33:41,805 [http-bio-8080-exec-3] DEBUG authentication.ProviderManager  - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2014-02-19 20:33:49,957 [http-bio-8080-exec-3] DEBUG hierarchicalroles.RoleHierarchyImpl  - getReachableGrantedAuthorities() - From the roles [ROLE_USER] one can reach [ROLE_USER] in zero or more steps.
2014-02-19 20:33:49,986 [http-bio-8080-exec-3] DEBUG rememberme.TokenBasedRememberMeServices  - Did not send remember-me cookie (principal did not set parameter '_spring_security_remember_me')
2014-02-19 20:33:49,989 [http-bio-8080-exec-3] DEBUG rememberme.TokenBasedRememberMeServices  - Remember-me login not requested.
2014-02-19 20:33:50,113 [http-bio-8080-exec-3] DEBUG web.DefaultRedirectStrategy  - Redirecting to '/app/organizations'
2014-02-19 20:33:50,114 [http-bio-8080-exec-3] DEBUG context.HttpSessionSecurityContextRepository  - HttpSession being created as SecurityContext is non-default
2014-02-19 20:33:50,199 [http-bio-8080-exec-3] DEBUG context.HttpSessionSecurityContextRepository  - SecurityContext stored to HttpSession: 'org.springframework.security.core.context.SecurityContextImpl@caf4192c: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@caf4192c: Principal: com.app.AppUserDetails@8ee96c84: Username: someuser; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: 10.0.2.2; SessionId: null; Granted Authorities: ROLE_USER'

Question: Creating a local account for the authenticated

A user authenticates for the first time using oauth provider
A local account needs to be created for that user.
What is the best way to achieve this:

  • implementing the TokenStorageService interface
  • customizing OauthService class
  • else / question doesn't make sense

Thanks

OauthUserDetailsService should check if the user is valid based on the UserProfile

OauthUserDetailsService contract should specify that implementations must throw an exception if the user received is not allowed to log into the system.

This is useful if we want to allow our corporate users to log into our application using their Gmail account. In this case, we should decide based on OAuth20Profile.getEmail(), for instance

java.lang.IllegalStateException: getWriter() has already been called on this response.

I was having a problem where the AuthenticationSuccessHandler was always spewing the json token to response for every call. This would cause any secured controllers using "render" or "respond" to fail with an exception:

java.lang.IllegalStateException: getWriter() has already been called on this response.

I overrode the SuccessHandler to only spew a json to the response if the call is a /login call. Because I have a custom security stack which sets the principal, I can tell whether it's a /login call by looking at the type of the principal in the AuthenticationSuccessHandler. This is very icky.

So, my questions:

  1. Is there a better way to tell if the current call is a /login?
  2. Am I doing something wrong which is causing this issue in the first place?
  3. Why does the type of the principal change depending on whether it's a /login or a tokenized call?

Add OAuth-like support for CAS

Please consider adding support for CAS as the SSO endpoint.

The basic sequence for authenticating against a JASIG CAS identity provider is the same as described in your docs for the OAuth sequence. Pac4j supports CAS already.

Where to store token on client

To prevent users from having to re log in when they close the tab and re open it, what do you think is the optimal solution to store tokens client side, if any?

Create a validate endpoint

It will receive a token, and if valid, will render a response using DefaultRestAuthenticationTokenJsonRenderer. Else, will return 404.

Normal web access is blocked

My website provides both REST API and some GSP pages. Both of them needs user log-in for access. However, after I enabled the plugin, my restricted GSP pages are also blocked. I wonder if there is anything I can change on Config.groovy to enable them again. I want "/api/*" to be protected by the REST plugin. Other folders or controllers should work in the original way. Is it possible to achieve that by tuning the configuration?

My GSP pages are protected in the controllers like the following:

@Secured('IS_AUTHENTICATED_REMEMBERED')
class BoardController {
    ......
}

Thanks a lot!
Jingzhao

Support "traditional" usage of Spring Security Core to coexist with Spring Security REST

This plugin was originally designed to be used in REST-only applications, because it offers endpoints to be consumed with pure Javascript frontend applications.

But it turns out that some users are applying this plugin to applications where "traditional" (form based) security is used.

To avoid clashing, the most important change is to not replace authenticationProcessingFilter bean, and to avoid listening by default on Spring Security Core default URL's.

Installation error pac4j

I am having problem with plugin install...

I put "compile..." command in BuildConfig then refresh dependecies and got this message:
"| Error Failed to resolve dependencies (Set log level to 'warn' in BuildConfig.groovy for more information): - org.pac4j:pac4j-oauth:1.5.0-SNAPSHOT"

Gorm token storage configuration

On the plugin documentation the configuration to store tokens as a GORM domain object uses the prefix:

grails.plugin.springsecurity.rest.token.storage.gorm.*

But trying it did't work.

When inspecting the code I've discovered that the class GormTokenStorageService.groovy uses the configuration prefix:

grails.plugin.springsecurity.rest.tokenRepository.*

So one or the other is incorrect.

Regards,

P.d. Great job with the plugin btw 👍

UnexpectedRollbackException

I'm trying to authenticate via Google and an exception occurs at String tokenValue = oauthService.storeAuthentication(provider, context)

I've tried memcached, gorm, custom implementation of token storage with the same result

http://pastebin.com/fHT2Ee5e

DEBUG oauth.DefaultOauthUserDetailsService - User not found. Creating a new one with default roles: [ROLE_USER, ROLE_GOOGLE]
DEBUG rest.OauthService - Generated REST authentication token: ppcitvann0kab5t79jpulltf0aomlubc
DEBUG rest.OauthService - Storing token on the token storage
DEBUG rest.OauthController - Redirecting to http://localhost:8080/MyApp#token=&error=500&message=Transaction+rolled+back+because+it+has+been+marked+as+rollback-only

UPDATE: Setting "static transactional = false" on OauthService fixed the problem for me, but I'm concerned that's a band-aid, which may cause other issues.
UPDATE: Apparently this is a bug in Grails 2.3.6 http://jira.grails.org/browse/GRAILS-11134

I'm probably doing something wrong - thanks for any help

TokenStorageService.storeToken called with non-UserDetails objects

This is related to issue #10, which is marked as closed. You decided to "fix" this issue with user documentation. My argument here is that that is not the appropriate fix.

In TokenStorageService, storeToken is defined as:

void storeToken(String tokenValue, UserDetails details)

But in RestAuthenticationFilter, it's called as:

tokenStorageService.storeToken(tokenValue, authenticationResult.principal)

According to the spring security javadocs for Authentication.getPrincipal():

The identity of the principal being authenticated. In the case of an authentication request with username and password, this would be the username.

It does continue on to say:

Many of the authentication providers will create a UserDetails object as the principal.

However, there's a big difference between allowing and requiring. My claim with this issue is that your code needs to support non-UserDetails objects because they are explicitly supported by Spring Security.

(And besides, anybody who is working with customized security components is not going to be rewriting their security code to meet your plugin's expectations.) ;)

If the OAuth authentication fails, it needs to redirect back to the frontend callback URL anyway

Currently, if the OAuth authentication fails (eg, because #26), the plugin renders an exception.

But that breaks the flow started from the frontend application. The flow must be completed, regardless of the status of the OAuth authentication. If successful, the tokenValue will be passed. Otherwise, an error code and message will be provided, so the frontend application has a chance to display a proper message.

Compilation error with Grails 2.2.x

Can't compile this plugin. First had the other pac4j problem (#14), but now I get this error:

| Compiling 212 source files.
| Error Fatal error during compilation org.apache.tools.ant.BuildException: java
.lang.NoClassDefFoundError: org/pac4j/core/client/BaseClient (Use --stacktrace t
o see the full trace)

Using grails 2.2.3. Tried cleaning .grails folder. Started with empty project.

Adding compile 'org.pac4j:pac4j-core:1.5.0-SNAPSHOT' in the buildconfig dependency block resolves the problem.

Installation error pac4j

Hi, I tried to use your plugin but after I put "compile..." command in BuildConfig then refresh dependecies to install the plugin and got this message:
"| Error Failed to resolve dependencies (Set log level to 'warn' in BuildConfig.groovy for more information): - org.pac4j:pac4j-oauth:1.5.0-SNAPSHOT"

Add support for GORM token expiration

I needed to be able to expire tokens. If GormTokenStorageService.findExistingToken had been protected instead of private I could have just overridden that and added a check against the AuthenticationToken domain object's createDate property.

Instead I had to implement the whole beast again with my own adjustments to findExistingToken.

My suggestion would be to make that method overridable. Or maybe you have a better idea of how I could handle this case?

Error while installing plugin

| Error Compilation error: startup failed:
C:\Users\nitish .grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\grails-app\controllers\com\odobo\grails\plugin\springsecurity\rest\OauthCont
groovy: 5: unable to resolve class org.pac4j.core.context.J2EContext
@ line 5, column 1.
import org.pac4j.core.context.J2EContext
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\grails-app\controllers\com\odobo\grails\plugin\springsecurity\rest\OauthCont
groovy: 6: unable to resolve class org.pac4j.core.context.WebContext
@ line 6, column 1.
import org.pac4j.core.context.WebContext
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\grails-app\controllers\com\odobo\grails\plugin\springsecurity\rest\OauthCont
groovy: 4: unable to resolve class org.pac4j.core.client.Client
@ line 4, column 1.
import org.pac4j.core.client.Client
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\src\groovy\com\odobo\grails\plugin\springsecurity\rest\oauth\DefaultOauthUse
sService.groovy: 4: unable to resolve class org.pac4j.core.profile.UserProfile
@ line 4, column 1.
import org.pac4j.core.profile.UserProfile
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\src\groovy\com\odobo\grails\plugin\springsecurity\rest\oauth\DefaultOauthUse
sService.groovy: 20: unable to resolve class org.pac4j.core.profile.UserProfile
@ line 20, column 37.
OauthUser loadUserByUserProfile(UserProfile userProfile, Collection defaultRoles) {
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\src\groovy\com\odobo\grails\plugin\springsecurity\rest\oauth\OauthUser.groov
nable to resolve class org.pac4j.core.profile.UserProfile
@ line 3, column 1.
import org.pac4j.core.profile.UserProfile
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\src\groovy\com\odobo\grails\plugin\springsecurity\rest\oauth\OauthUser.groov
unable to resolve class org.pac4j.core.profile.UserProfile
@ line 13, column 5.
UserProfile userProfile
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\src\groovy\com\odobo\grails\plugin\springsecurity\rest\oauth\OauthUser.groov
unable to resolve class org.pac4j.core.profile.UserProfile
@ line 19, column 101.
rantedAuthority> authorities, UserProfil
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\src\groovy\com\odobo\grails\plugin\springsecurity\rest\oauth\OauthUserDetail
e.groovy: 3: unable to resolve class org.pac4j.core.profile.UserProfile
@ line 3, column 1.
import org.pac4j.core.profile.UserProfile
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\src\groovy\com\odobo\grails\plugin\springsecurity\rest\oauth\OauthUserDetail
e.groovy: 12: unable to resolve class org.pac4j.core.profile.UserProfile
@ line 12, column 37.
OauthUser loadUserByUserProfile(UserProfile userProfile, Collection defaultRoles)
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\grails-app\services\com\odobo\grails\plugin\springsecurity\rest\OauthService
: 10: unable to resolve class org.pac4j.core.context.WebContext
@ line 10, column 1.
import org.pac4j.core.context.WebContext
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\grails-app\services\com\odobo\grails\plugin\springsecurity\rest\OauthService
: 11: unable to resolve class org.pac4j.core.credentials.Credentials
@ line 11, column 1.
import org.pac4j.core.credentials.Credentials
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\grails-app\services\com\odobo\grails\plugin\springsecurity\rest\OauthService
: 12: unable to resolve class org.pac4j.core.profile.UserProfile
@ line 12, column 1.
import org.pac4j.core.profile.UserProfile
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\grails-app\services\com\odobo\grails\plugin\springsecurity\rest\OauthService
: 9: unable to resolve class org.pac4j.core.client.Client
@ line 9, column 1.
import org.pac4j.core.client.Client
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\grails-app\services\com\odobo\grails\plugin\springsecurity\rest\OauthService
: 31: unable to resolve class org.pac4j.core.client.Client
@ line 31, column 5.
Client getClient(String provider) {
^

C:\Users\nitish.grails\2.2.1\projects\restapp\plugins\spring-security-rest-1.2.5\grails-app\services\com\odobo\grails\plugin\springsecurity\rest\OauthService
: 48: unable to resolve class org.pac4j.core.context.WebContext
@ line 48, column 49.
thentication(String provider, WebContext

any suggestion, anything I am missing ?

Missing method "getRedirectionUrl"

First of all, great plugin!

I stumbled across an issue with pac4j dependency. Looks lite the pac4j team remove the "getRedirectionUrl" method from BaseOAuthClient impl, which lead to a missingmethod exception.

pac4j commit

MissingMethodException occurred when processing request: [GET] /oauth/authenticate/facebook
No signature of method: org.pac4j.oauth.client.FacebookClient.getRedirectionUrl() is applicable for argument types: (org.pac4j.core.context.J2EContext, java.lang.Boolean, java.lang.Boolean) values: [org.pac4j.core.context.J2EContext@4eab5d8d, ...]. Stacktrace follows:
Message: No signature of method: org.pac4j.oauth.client.FacebookClient.getRedirectionUrl() is applicable for argument types: (org.pac4j.core.context.J2EContext, java.lang.Boolean, java.lang.Boolean) values: [org.pac4j.core.context.J2EContext@4eab5d8d, ...]
    Line | Method
->>   26 | authenticate       in com.odobo.grails.plugin.springsecurity.rest.OauthController
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|     88 | processFilterChain in com.odobo.grails.plugin.springsecurity.rest.RestTokenValidationFilter
|     66 | doFilter . . . . . in     ''
|     53 | doFilter           in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
|    108 | doFilter . . . . . in com.odobo.grails.plugin.springsecurity.rest.RestAuthenticationFilter
|     49 | doFilter           in grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
|     82 | doFilter . . . . . in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
|     66 | doFilter           in com.odobo.grails.plugin.springsecurity.rest.RestLogoutFilter
|     82 | doFilter . . . . . in com.brandseye.cors.CorsFilter
|   1145 | runWorker          in java.util.concurrent.ThreadPoolExecutor
|    615 | run . . . . . . .  in java.util.concurrent.ThreadPoolExecutor$Worker

I created a fix for the issue in OauthController which seems to work.

    /**
     * Starts the OAuth authentication flow, redirecting to the provider's Login URL. An optional callback parameter
     * allows the frontend application to define the frontend callback URL on demand.
     */
    def authenticate(String provider, String callback) {
        BaseOAuthClient client = oauthService.getClient(provider)
        WebContext context = new J2EContext(request, response)

        RedirectAction  redirectionUrl = client.getRedirectAction(context, true, false)

        if (callback) {
            log.debug "Trying to store in the HTTP session a user specified callback URL: ${callback}"
            try {
                new URL(callback)
                session[CALLBACK_ATTR] = callback
            } catch (MalformedURLException mue) {
                log.warn "The URL is malformed. Not storing it."
            }
        }

        log.debug "Redirecting to ${redirectionUrl}"
        redirect url: redirectionUrl.location
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.