Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Álvaro Sánchez-Mariscal
@alvarosanchez
I think the mentioned PR needs further discussion
is not that simple
Florent Blanvillain
@florent-blanvillain
@alvarosanchez I'm interested in the switch-user functionality, as discussed in alvarosanchez/grails-spring-security-rest#125. However I unfortunately need it now :-D More seriously, could you give me some precise pointers to do the simplest switch user functionality possible ? I don't need to be able to switch back, I don't even need to know that the current user has been switched to. All I need is for an admin user to be (re)authenticated as a given other user with its username via a POST. From what you describe as what would be necessary to implement the switch-user-spring-security-like functionality, I guess the authentication as another user is not the most complex part; but I have no idea where to begin with. Thanks a lot and sorry..
Yanis Ikene
@yanisIk

Hello Alvaro, first I would like to thank you for this wonderful plugin.
However, your plugin doesn't answer to all my needs so I decided to modify it and I want to ask you if this is correct and if you can do it in a future release too.

So, what I need is OAuth but with the client sending the oauth token (for usage with a mobile app for example). Your plugin only allows to OAuth with a website client side, but not with other type of clients like mobile apps.
So here's the new flow :

1) Client authenticate to provider and receives informations.
2) Client login to our grails app : api/authenticate/{provider}
3) The modified RestOAuthController does the following :

    @Secured(['permitAll'])
class RestOauthController extends RestController{
    static responseFormats = ['json']
    static allowedMethods = [authenticate: "POST"]

    def restOauthService

    //Client OAuth flow only
    def authenticate(String provider){

        BaseOAuthClient client = restOauthService.getClient(provider)
        WebContext context = new J2EContext(request, response)

        try {
                String tokenValue = restOauthService.storeAuthentication(provider, context)
        } 
        catch (Exception e) {
                String errorParams
                if (e instanceof UsernameNotFoundException) {
                    restOauthService.registerUser(provider, context) 
                    //Is this necessary or is it already done in DefaultOauthUserDetailsService in catch (UsernameNotFoundException unfe) log.debug "User not found. Creating a new one with default roles: ${defaultRoles}"
                } else {
                    respond ["error" : "&error=${e.cause?.code?:500}&message=${e.message?.encodeAsURL()?:''}"]
                }
        }
        log.debug "Returning access_token in json"
        respond [''access_token'' : tokenValue]
    }    
    }
}
Yanis Ikene
@yanisIk

4) The client sends back this token in each request

My questions :
1) How do I access the logged user (MyUser not Spring's User) in a controller :
Example :

  class MyUser{
        User user //Spring security User
        static hasOne = ['user']
        static hasMany = [dogs : Dog]
  }
  class Dog{
        MyUser owner
        String name
        static belongsTo = ['owner']
   }
  class DogRestController extends RestController{
        .....
        @Secured['ROLE_USER']
         def index(){
             MyUser myUser = getAuthenticatedUser() //Spring security metaclass method
              //Will this map correctly the User to MyUser ? is my domain well defined ? 
             respond Dog.findAllByOwner(myUser)
          } 
    }
Yanis Ikene
@yanisIk

I also modified RestOauthService to create a new MyUser when this is the first time OAuth Login/Signup

String storeAuthentication(String provider, WebContext context) {
    .......
    try{
            //is created even if first time login/signup
    OauthUser userDetails = oauthUserDetailsService.loadUserByUserProfile(profile, defaultRoles)
}
catch (UsernameNotFoundException unfe) {
    log.debug "MyUser not found. Creating a new one"
    registerMyUser(userDetails)
}
     ....
}

/** Register a new MyUser with the informations contained in OAuth profile **/
@Transactional
def registerMyUser(OauthUser user){

CommonProfile profile = user.userProfile

Address address = new Address(city: profile.location)
Profile profile = new Profile(name:profile.displayName, emailAddress:profile.email, photoUrl:profile.pictureUrl, address:address )

HobdyUser hobdyUser = new HobdyUser(user: user, profile: profile)

hobdyUser.save() //Do not flush
}    

Is this the correct way to do it ?

Thanks.

Florent Blanvillain
@florent-blanvillain

Following my question, I think I found the answer and it was incredibly simple !!
Here is a controller's action that seems to do the job:

def switchUser() {
    def username = params.username
    def principal = userDetailsService.loadUserByUsername(username)
    if (principal) {
        def oldToken = request.getHeader("X-Auth-Token")
        tokenStorageService.removeToken(oldToken)

        def newToken = new SecureRandomTokenGenerator().generateToken()
        tokenStorageService.storeToken(newToken, principal)
        render(contentType: "text/json") {
            [
                    username    : username,
                    roles       : principal.authorities.authority,
                    access_token: newToken
            ]
        }
    } else {
        render status: 404
    }
}

Thanks

Yanis Ikene
@yanisIk
I also found something exploitable : Let's say I signup with OAuth, then a user will be created with my id and no password. Then let's say I login after that using /api/login and just enter my id and N/A password, will it login ? Do I have to modify the login controller too ?
Álvaro Sánchez-Mariscal
@alvarosanchez
@florent-blanvillain you should have a look at #131. There is lots of useful information there
@florent-blanvillain ok, I just read your latest comment :) Few comments on your code
1) To get the current principal you don't need to load it again. Just use springSecurityService.principal (inject that bean in your controller)
2) The header name can be customised in Config.groovy, so you better don't hardcode it just in case
3) Inject tokenGenerator bean instead of manually building an instance of one of them
Oh, forget about 1), I just realised is not the current principal, but the new one...
Álvaro Sánchez-Mariscal
@alvarosanchez
@skini26 about the OAuth delegation support, it is only for web based applications because I use the implicit grant support of those providers
To access the current user you can use springSecurityService.currentUser
Regarding the exploit you mention, if you are not using it, you can disable the login endpoint. Otherwise, you should have to generate a random password to avoid that
Florent Blanvillain
@florent-blanvillain
@alvarosanchez thanks :-D
Yanis Ikene
@yanisIk

@alvarosanchez thanks :) (I know the code I wrote has a lot of wrong things, sorry about that, I just figured them out after but I can't edit anymore).

Another question : Is there a controller already available for registering users ? I found nothing in SS core, maybe I missed it.
And the springSecurityService.currentUser will return me the Spring Security User and not my custom User. So do you suggest me to modify the generated User by SpringSecurity Core (as suggested by their documentation), or to extend it or to have a reference to it ?

Thanks.

Álvaro Sánchez-Mariscal
@alvarosanchez
@skini26 springSecurityService.currentUser should return your DB user. The other one is springSecurityService.principal. Have you tried both to see the results?
Robert Oschwald
@robertoschwald
Hi Alvaro. Thanks for your plugin. Just a quick note: I use your plugin for IOS App REST Auth to a Grails server application, so the scope of the plugin is much wider than just decoupling HTML frontends.
Siim Talvik
@simpss

Hi, i'm having a problem getting my requests authenticated, I get a 401 every time. The credentials can be checked and a token is received. the relevant config.groovy

// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.usernamePropertyName='email'
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.saas.user.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.saas.user.UserRole'
grails.plugin.springsecurity.authority.className = 'com.saas.user.Role'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
        '/':               ['permitAll'],
        '/index':          ['permitAll'],
        '/index.gsp':      ['permitAll'],
        '/assets/**':      ['permitAll'],
        '/**/js/**':       ['permitAll'],
        '/**/css/**':      ['permitAll'],
        '/**/images/**':   ['permitAll'],
        '/**/favicon.ico': ['permitAll']
]
grails.plugin.springsecurity.filterChain.chainMap = [
        '/api/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter',  // Stateless chain
        '/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'                                                                          // Traditional chain
]

//spring security rest configuration
grails.plugin.springsecurity.rest.token.storage.useGorm = true
grails.plugin.springsecurity.rest.token.storage.gorm.tokenDomainClassName = 'com.saas.user.SaasToken'
grails.plugin.springsecurity.rest.token.storage.gorm.tokenValuePropertyName = 'tokenValue'
grails.plugin.springsecurity.rest.token.storage.gorm.usernamePropertyName = 'email'

grails.plugin.springsecurity.rest.login.useJsonCredentials = true
grails.plugin.springsecurity.rest.login.usernamePropertyName = 'email'
grails.plugin.springsecurity.rest.login.passwordPropertyName = 'password'

grails.plugin.springsecurity.rest.token.validation.active   = true
grails.plugin.springsecurity.rest.token.validation.headerName = 'X-Auth-Token'
grails.plugin.springsecurity.rest.token.validation.endpointUrl  = '/api/validate'

request to localhost:8080/rest_api/api/validate. the token exists in the DB so that should be OK. tried it with and without 'Bearer', Tried changing the headerName configuration, nothing...
and the request header i'm using is, :

X-Auth-Token:Bearer i64fli2k08kifvf7d771uib45dsrbdfd
not really sure what's gone wrong, thought i'd drop by and ask for a bit of help
Siim Talvik
@simpss
Looks like i got it working by using "Authorization:Bearer tokenValue", knew it was something simple :)
ericbai
@ericbai
Hi everyone! First off, thank you for creating such a useful plugin! There's something strange going on with my grails app that I've been struggling with for the past few weeks. After installing Spring Security REST and Spring Security Core to secure the RESTful API I'm trying to build, every time I write to the database (for example call save on a new object) I get the error seen below. Any thought on what might be going on? java.lang.instrument ASSERTION FAILED : "!errorOutstanding" with message transform method call failed at ../.|
Lawrence Lee
@ChaosWars
Is this compatible with Hibernate 4? I am getting an error: 2015-03-11 10:58:55,142 [localhost-startStop-1] ERROR hbm2ddl.SchemaUpdate - HHH000388: Unsuccessful: alter table activity add constraint FK_asrd0n4f4lih436go65u6dakp foreign key (next_id) references activity
Error |
2015-03-11 10:58:55,143 [localhost-startStop-1] ERROR hbm2ddl.SchemaUpdate - Constraint "FK_ASRD0N4F4LIH436GO65U6DAKP" already exists; SQL statement:
alter table activity add constraint FK_asrd0n4f4lih436go65u6dakp foreign key (next_id) references activity [90045-176]
Then when I attempt to log in, the following logs are generated: 015-03-11 10:59:02,000 [http-bio-8080-exec-1] DEBUG matcher.AntPathRequestMatcher - Request '/login' matched by universal pattern '/**'
2015-03-11 10:59:02,001 [http-bio-8080-exec-1] DEBUG web.FilterChainProxy - /login at position 1 of 8 in additional filter chain; firing Filter: 'RestLogoutFilter'
2015-03-11 10:59:02,011 [http-bio-8080-exec-1] DEBUG web.FilterChainProxy - /login at position 2 of 8 in additional filter chain; firing Filter: 'MutableLogoutFilter'
2015-03-11 10:59:02,011 [http-bio-8080-exec-1] DEBUG web.FilterChainProxy - /login at position 3 of 8 in additional filter chain; firing Filter: 'RestAuthenticationFilter'
2015-03-11 10:59:02,011 [http-bio-8080-exec-1] DEBUG rest.RestAuthenticationFilter - Actual URI is /login; endpoint URL is /login
2015-03-11 10:59:02,011 [http-bio-8080-exec-1] DEBUG rest.RestAuthenticationFilter - Applying authentication filter to this request
2015-03-11 10:59:02,028 [http-bio-8080-exec-1] DEBUG credentials.DefaultJsonPayloadCredentialsExtractor - Extracted credentials from JSON payload. Username: some@email.com, password: [PROTECTED]
2015-03-11 10:59:02,033 [http-bio-8080-exec-1] DEBUG rest.RestAuthenticationFilter - Trying to authenticate the request
2015-03-11 10:59:02,036 [http-bio-8080-exec-1] DEBUG authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2015-03-11 10:59:02,080 [http-bio-8080-exec-1] DEBUG rest.RestAuthenticationFilter - Authentication failed: Could not obtain current Hibernate Session; nested exception is org.hibernate.HibernateException: No Session found for current thread
2015-03-11 10:59:02,082 [http-bio-8080-exec-1] DEBUG bearer.BearerTokenReader - Looking for bearer token in Authorization header, query string or Form-Encoded body parameter
2015-03-11 10:59:02,083 [http-bio-8080-exec-1] DEBUG bearer.BearerTokenReader - No token found
2015-03-11 10:59:02,084 [http-bio-8080-exec-1] DEBUG bearer.BearerTokenAuthenticationFailureHandler - Sending status code 401 and header WWW-Authenticate: Bearer
2015-03-11 10:59:02,084 [http-bio-8080-exec-1] DEBUG rest.RestAuthenticationFilter - Not authenticated. Rest authentication token not generated.
It all works with Hibernate 3
Álvaro Sánchez-Mariscal
@alvarosanchez
@ChaosWars the alter table error has nothing to do with the plugin, but with your domain, your dbCreate and your database
apart from that, there is a No Session found for current thread exception before the authentication fails
This plugin doesn't care about Hibernate, so my guess is that maybe Spring Security Core does not work with Hibernate 4, I don't know
However, in the company I work for, I can confirm you that we use this plugin, Hibernate 4 and the DaoAuthenticationProvider, and it all works
Lawrence Lee
@ChaosWars
Ok, good to know
However, this plugin depends on a version of Spring Security Core. Can you tell me which version of Spring Security Core you are using? And which version of this plugin?
Álvaro Sánchez-Mariscal
@alvarosanchez
SS Core 2.0-RC4 and SS Rest 1.4.1 (latest stable)
Lawrence Lee
@ChaosWars
Thanks. It turned out to be the darndest thing. We were using the build-test-data plugin, and it's annotations were wreaking havoc throughout our program. This and other bugs were caused by it
Álvaro Sánchez-Mariscal
@alvarosanchez
allright then
Tushar Saxena
@tushar-saxena
Hi. do we need to run s2- quickstart in spring security rest plugin?
Álvaro Sánchez-Mariscal
@alvarosanchez
@tushar-saxena not for the REST plugin, but you might do it for the Core plugin
Tushar Saxena
@tushar-saxena
@alvarosanchez thanks
willowsmyth
@willowsmyth
Hi, I have a working application without SS-core and SS-rest, but as soon as I install both of the plugins, requesting appname/index.gsp (as well as api/login) renders a 404.
willowsmyth
@willowsmyth
Finally got an error out of grails that lead to a change to file: ./target/work/plugins/cors-1.1.6/CorsGrailsPlugin.groovy. Had to change plugins.springsecurity to plugin.springsecurity
I was using compile ':spring-security-core:2.0-SNAPSHOT' & compile ":spring-security-rest:1.5.0.M2"
dcalleg
@dcalleg
@alvarosanchez , Hi Alvaro, I'm new using your plugin. I need to do a oauth authentication from mobile apps. Is it possible do that with this plugin?
Thanks
Álvaro Sánchez-Mariscal
@alvarosanchez
@dcalleg you need OAuth with 3rd party providers like Google/Facebook/Twitter?
If that's the case, then yes, the plugin is useful
If you need to become your own OAuth provider, then I recommend you this: https://grails.org/plugin/spring-security-oauth2-provider
@neoecos very good point about JWT, I will think about a generic plugin
dcalleg
@dcalleg
@alvarosanchez , Thanks