I tried the example, on the scribe page, but with a callback. I always get the error "Could not authenticate with OAuth." the moment i try to use the returned access token.
service = new ServiceBuilder()
.provider(TwitterApi.class)
.apiKey(config.getTwitterKey())
.apiSecret(config.getTwitterSecret())
.callback(config.getServerPath()+"/oauth/twitter")
.build();
Token requestToken = service.getRequestToken();
service.getAuthorizationUrl(requestToken)
On the callback then i tried 2 different things, using the request token from the first step or new Token(tokenParam,verifier) but makes no difference, both return a access token that is not working.
String tokenParam = request.getParameter(TOKEN);
String verifier = request.getParameter(VERIFIER);
Token accessToken = service.getAccessToken(requestToken,new Verifier(verifier));
The response stream with the access token contains user id and display name, so until this step everything seems ok.
OAuthRequest request = new OAuthRequest(Verb.GET, "https://api.twitter.com/1/account/verify_credentials.json");
service.signRequest(accessToken, request); // the access token from step 4
request.send().getBody();
i tried using the xml url and the json url, but i keep getting the error message in the getBody() method. {"error":"Could not authenticate with OAuth.","request":"\/1\/account\/verify_credentials.json"}
EDIT:
Scribe Debug Output:
Getting the Access Token
15:01:08,136 INFO [STDOUT] obtaining request token from https://api.twitter.com/oauth/request_token
15:01:08,141 INFO [STDOUT] setting oauth_callback to http://127.0.0.1:8080/myapp/oauth/twitter
15:01:08,145 INFO [STDOUT] generating signature...
15:01:08,380 INFO [STDOUT] base string is: POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttp%253A%252F%252F127.0.0.1%253A8080%252Fmyapp%252Foauth%252Ftwitter%26oauth_consumer_key%3DXXXXXXXXXX%2520%26oauth_nonce%3D583776017%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1346763668%26oauth_version%3D1.0
15:01:08,380 INFO [STDOUT] signature is: FagkFuKWHMRfoAQFS4tmMMO9FvI=
15:01:08,381 INFO [STDOUT] appended additional OAuth parameters: { oauth_callback -> http://127.0.0.1:8080/myapp/oauth/twitter , oauth_signature -> FagkFuKWHMRfoAQFS4tmMMO9FvI= , oauth_version -> 1.0 , oauth_nonce -> 583776017 , oauth_signature_method -> HMAC-SHA1 , oauth_consumer_key -> XXXXXXXXXX , oauth_timestamp -> 1346763668 }
15:01:08,382 INFO [STDOUT] using Http Header signature
15:01:08,383 INFO [STDOUT] sending request...
15:01:09,564 INFO [STDOUT] response status code: 200
15:01:09,564 INFO [STDOUT] response body: oauth_token=dr7cT1xxxxK777Op7fjXeDMCqlY2DdAyyECLnVbhqLI&oauth_token_secret=xxxxxc7qB6pAzjnDrk3fDirakPVKxlS9c&oauth_callback_confirmed=true
Sending the signed request
15:01:14,851 INFO [STDOUT] obtaining access token from https://api.twitter.com/oauth/access_token
15:01:14,852 INFO [STDOUT] setting token to: Token[dr7cTxxxxxXeDMCqlY2DdAyyECLnVbhqLI , 9ME2xglzfa0xxxxrk3fDirakPVKxlS9c] and verifier to: org.scribe.model.Verifier#96cb5a
15:01:14,852 INFO [STDOUT] generating signature...
15:01:14,853 INFO [STDOUT] base string is: POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Faccess_token&oauth_consumer_key%3DXXXXXXXXXXXX%2520%26oauth_nonce%3D2130885611%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1346763674%26oauth_token%3Ddr7cTxxxxxXeDMCqlY2DdAyyECLnVbhqLI%26oauth_verifier%3DrbRauznYtglz0eKDtCz7B2yeM%26oauth_version%3D1.0
15:01:14,853 INFO [STDOUT] signature is: OPJPKxP6veY/U/Fc9ZQU4a7vkaQ=
15:01:14,854 INFO [STDOUT] appended additional OAuth parameters: { oauth_signature -> OPJPKxP6veY/U/Fc9ZQU4a7vkaQ= , oauth_version -> 1.0 , oauth_nonce -> 2130885611 , oauth_signature_method -> HMAC-SHA1 , oauth_consumer_key -> XXXXXXXXXXXXXXX , oauth_token -> dr7cT1SLFaK77DdAyyECLnVbhqLI , oauth_verifier -> rbRauznYtgugBLzgQRlz0eKDtCz7B2yeM , oauth_timestamp -> 1346763674 }
15:01:14,854 INFO [STDOUT] using Http Header signature
15:01:15,792 INFO [STDOUT] signing request: https://api.twitter.com/1/account/verify_credentials.json
15:01:15,792 INFO [STDOUT] setting token to: Token[15751501-mQZHUAHIzPrYUjwfD4IWvQunC3tTKdUIT4AmdjNvQ , Iw0pNVkhB5Ld4J36sZtiEmawH8XHR9hgvBNgAseTj0]
15:01:15,792 INFO [STDOUT] generating signature...
15:01:15,796 INFO [STDOUT] base string is: GET&https%3A%2F%2Fapi.twitter.com%2F1%2Faccount%2Fverify_credentials.json&oauth_consumer_key%3DXXXXXXXXXXXXXXXXX%2520%26oauth_nonce%3D139442186%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1346763675%26oauth_token%3D15751501-mQZHUAHIzPrYUjwfD4IWvQunC3tTKdUIT4AmdjNvQ%26oauth_version%3D1.0
15:01:15,796 INFO [STDOUT] signature is: SziWPSPcEKRq0UE2AvkGvf8rIuo=
15:01:15,797 INFO [STDOUT] appended additional OAuth parameters: { oauth_signature -> SziWPSPcEKRq0UE2AvkGvf8rIuo= , oauth_version -> 1.0 , oauth_nonce -> 139442186 , oauth_signature_method -> HMAC-SHA1 , oauth_consumer_key -> XXXXXXXXXXXXXXXXXX , oauth_token -> 15751501-mQZHUAHIzPrYUjwfD4IWvQunC3tTKdUIT4AmdjNvQ , oauth_timestamp -> 1346763675 }
15:01:15,797 INFO [STDOUT] using Http Header signature
15:01:17,801 INFO [STDOUT] {"error":"Could not authenticate with OAuth.","request":"\/1\/account\/verify_credentials.json"}
Related
I'm following along with this 2-part tutorial.
Part 1
Part 2
The goal described:
The API Gateway will serve as example of performing an OAuth 2
Authorization code flow based Login with session management.
Furthermore it will display how to augment HTTP requests with the
proper OAuth bearer token as required by the resource server. Key
take-away being that the access/refresh token as acquired from
Keycloak will never be exposed to the browser.
The difference is that I'm not leveraging Keycloak, I am using Login.gov, and -- from my experience -- integrating with them can be quite painful, despite their decent documentation
The problem:
The tutorial thinks I can get away with something as basic as:
...
.oauth2Login()
Previously, when I was NOT using a gateway paradigm or reactive programming model, I had done a lot of tweaking of oauth on my security config to integrate with Login.gov, such as:
...
.oauth2Login()
.loginPage(DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL)
.authorizationEndpoint()
.authorizationRequestResolver(new LoginGovAuthorizationRequestResolver(clientRegistrationRepository))
.authorizationRequestRepository(authorizationRequestRepository())
.and()
.tokenEndpoint()
.accessTokenResponseClient(accessTokenResponseClient())
.and()
.failureHandler(new LoginGovAuthenticationFailureHandler())
.successHandler(new LoginGovAuthenticationSuccessHandler())
There's obviously a lot going on here, but the point is: all those jumping through hoops was mostly to do a couple things (that I can remember):
add 2 params in the request resolver
acr_values (constant: could be added in config authorization_uri)
nonce (22-character min, and at least then required a resolver)
additionalParameters.put("acr_values", LoginGovConstants.LOGIN_GOV_LOA1)
additionalParameters.put("nonce", nonce)
Furthermore, the converter apparently necessitated me signing my own JWT and providing it client_assertion and the constant client_assertion_type parameters:
#Override
RequestEntity<?> convert(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
RequestEntity<?> originalRequestEntity = super.convert(authorizationCodeGrantRequest)
String registrationId = resolveRegistrationId(authorizationCodeGrantRequest)
if(registrationId == LoginGovConstants.LOGIN_GOV_REGISTRATION_ID) {
ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(registrationId)
String clientId = clientRegistration.clientId
String clientSecret = clientRegistration.clientSecret
String tokenUri = clientRegistration.providerDetails.tokenUri
Long expirationTime = LoginGovConstants.LOGIN_GOV_TOKEN_EXPIRATION_TIME
String jwt = JWT.create()
.withSubject(clientId)
.withIssuer(clientId)
.withAudience(tokenUri)
// Should be an un-guessable, random string generated by the client
.withJWTId(UUID.randomUUID().toString())
.withExpiresAt(new Date(System.currentTimeMillis() + expirationTime))
.sign(Algorithm.RSA256(keystoreUtil.rsaPublicKey(), keystoreUtil.rsaPrivateKey()))
HttpHeaders headers = originalRequestEntity.headers
MultiValueMap<String, String> formParameters = originalRequestEntity.body as MultiValueMap<String, String>
URI uri = originalRequestEntity.url
formParameters.add("client_assertion", jwt)
formParameters.add("client_assertion_type", LoginGovConstants.LOGIN_GOV_CLIENT_ASSERTION_TYPE)
return new RequestEntity<?>(formParameters, headers, HttpMethod.POST, uri)
}
}
Suffice to say, at the time I implemented my previous solution, it seemed like a lot of backflips to accomplish some extra URL parameters that I thought Spring Security should provide by default. So if we can improve on my previous appraoch, I would appreciate some guidance.
Nevertheless, with this new API gateway approach, I'm further confused, considering Webflux and a reactive paradigm.
For example:
OAuth2AuthorizationCodeGrantRequestEntityConverter vs. ServerOAuth2AuthorizationCodeAuthenticationTokenConverter
OAuth2AuthorizationRequestResolver vs. ServerOAuth2AuthorizationRequestResolver
What is the overlap between these classes, if any?
Is there an easier way to accomplish what I had previously done with these different Server* classes?
Current behavior:
Following the tutorial I mentioned, I have a partial flow going with my gateway, but the picture is not complete:
spring:
application:
name: gateway
security:
oauth2:
client:
registration:
login-gov:
client-id: \${LOGIN_GOV_CLIENT_ID}
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
scope:
- openid
- email
provider:
login-gov:
authorization-uri: https://idp.int.identitysandbox.gov/openid_connect/authorize
token-uri: https://idp.int.identitysandbox.gov/api/openid_connect/token?client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
user-info-uri: https://idp.int.identitysandbox.gov/api/openid_connect/userinfo
jwk-set-uri: https://idp.int.identitysandbox.gov/api/openid_connect/certs
user-name-attribute: sub
Login.gov is using the private_key_jwt authentication method, and that seems to mean I have no "client-secret". Is this why it was necessary for me to create and sign my own JWT in my previous implementation?
This is the output of the gateway when I've hit a gateway endpoint (/api/user/api/v1/savesearches/) that should eventually redirect to an actual service.
The login flow initiates as expected, and I enter my credentials on the integration Login.gov page. Once I submit, I am ultimately redirected back to an error page /login?error
2020-04-20 14:10:30.934 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-10] HTTP GET "/api/user/api/v1/savesearches/"
2020-04-20 14:10:30.983 DEBUG 15352 --- [oundedElastic-2] o.s.w.s.s.DefaultWebSessionManager : Created new WebSession.
2020-04-20 14:10:30.995 DEBUG 15352 --- [oundedElastic-2] .s.u.m.MediaTypeServerWebExchangeMatcher : httpRequestMediaTypes=[text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8]
2020-04-20 14:10:30.996 DEBUG 15352 --- [oundedElastic-2] .s.u.m.MediaTypeServerWebExchangeMatcher : Processing text/html
2020-04-20 14:10:30.996 DEBUG 15352 --- [oundedElastic-2] .s.u.m.MediaTypeServerWebExchangeMatcher : text/html .isCompatibleWith text/html = true
2020-04-20 14:10:30.997 DEBUG 15352 --- [oundedElastic-2] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-10] Completed 302 FOUND
2020-04-20 14:10:31.006 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-11] HTTP GET "/oauth2/authorization/login-gov"
2020-04-20 14:10:31.017 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-11] Completed 302 FOUND
2020-04-20 14:10:31.853 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-12] HTTP GET "/api/user/api/v1/savesearches/"
2020-04-20 14:10:31.861 DEBUG 15352 --- [ctor-http-nio-5] .s.u.m.MediaTypeServerWebExchangeMatcher : httpRequestMediaTypes=[text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8]
2020-04-20 14:10:31.861 DEBUG 15352 --- [ctor-http-nio-5] .s.u.m.MediaTypeServerWebExchangeMatcher : Processing text/html
2020-04-20 14:10:31.861 DEBUG 15352 --- [ctor-http-nio-5] .s.u.m.MediaTypeServerWebExchangeMatcher : text/html .isCompatibleWith text/html = true
2020-04-20 14:10:31.861 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-12] Completed 302 FOUND
2020-04-20 14:10:31.868 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-13] HTTP GET "/oauth2/authorization/login-gov"
2020-04-20 14:10:31.874 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-13] Completed 302 FOUND
2020-04-20 14:10:44.361 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-14] HTTP GET "/login/oauth2/code/login-gov?code=d2236ca8-1458-4631-b067-057f461d2a71&state=pp0V-IpV75MSgq995i5IUoQvuaFGhBXBJyRiHsAhQvM%3D"
2020-04-20 14:10:44.382 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.r.f.client.ExchangeFunctions : [312e7ca5] HTTP POST https://idp.int.identitysandbox.gov/api/openid_connect/token?client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
2020-04-20 14:10:44.950 DEBUG 15352 --- [ctor-http-nio-5] org.springframework.web.HttpLogging : [312e7ca5] Writing form fields [grant_type, code, redirect_uri, client_id, code_verifier] (content masked)
2020-04-20 14:10:45.080 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.r.f.client.ExchangeFunctions : [312e7ca5] Response 400 BAD_REQUEST
2020-04-20 14:10:45.094 DEBUG 15352 --- [ctor-http-nio-5] org.springframework.web.HttpLogging : [312e7ca5] Decoded [{error=Client assertion Nil JSON web token}]
2020-04-20 14:10:45.095 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-14] Completed 302 FOUND
2020-04-20 14:10:45.099 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-15] HTTP GET "/login?error"
2020-04-20 14:10:45.101 DEBUG 15352 --- [ctor-http-nio-5] o.s.w.s.adapter.HttpWebHandlerAdapter : [eae7892d-15] Completed 200 OK
What stands out to me is very clear here. I can see the authorization step succeed, as indicated by the redirect to /login/oauth2/code/login-gov?code=d2236ca8-1458-4631-b067-057f461d2a71&state=pp0V-IpV75MSgq995i5IUoQvuaFGhBXBJyRiHsAhQvM%3D with the code and state parameters existing.
What is confusing are the parameters provided to the the token endpoint: it only has the client_assertion_type that I provided in the config above, but it should have the actual client_assertion (JWT) too. I presume, this is all the hoop-jumping I had done before to create a JWT in the custom converter, but I never understood why Spring didn't do this for me?
Am I missing some basic configuration step? If not, I could use some help to re-implement the converter in a reactive (ServerWebExchange) kind of way.
Thank you for your patience.
FYI Spring Security 5 does not yet support private_key_jwt which is why you're having to do extra work to get it working.
(Adding an answer as I don't have enough reputation to comment)
I am trying to implement grails-spring-security-rest plugin for a Grails 3.1.7 project. The JWT token generated on the server does not match the one returned to the client.
I also tried validating the returned tokwn on https://jwt.io/ but I get a "Invalid Token"
What am I doing wrong? Below is the logs I see on the server
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/assets/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/**/js/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/**/css/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/**/images/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/**/favicon.ico'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/api/**'
DEBUG org.springframework.security.web.FilterChainProxy - / has no matching filters
DEBUG grails.plugin.springsecurity.rest.token.bearer.BearerTokenReader - Looking for bearer token in Authorization header, query string or Form-Encoded body parameter
DEBUG grails.plugin.springsecurity.rest.token.bearer.BearerTokenReader - No token found
DEBUG grails.plugin.springsecurity.rest.token.bearer.BearerTokenReader - Token: null
DEBUG grails.plugin.springsecurity.rest.RestTokenValidationFilter - Token not found
DEBUG grails.plugin.springsecurity.rest.RestTokenValidationFilter - Request does not contain any token. Letting it continue through the filter chain
DEBUG grails.plugin.springsecurity.rest.RestAuthenticationFilter - Actual URI is /; endpoint URL is /api/login
DEBUG org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/bootstrap/bootstrap.css'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/bootstrap/bootstrap.css?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/mobile.css'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/mobile.css?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/grails.css'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/grails.css?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/application.css'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/application.css?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/main.css'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/main.css?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/angular/angular.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/angular/angular.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/angular/angular-cookies.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/angular/angular-cookies.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/angular/angular-resource.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/angular/angular-resource.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/angular/angular-route.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/angular/angular-route.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/angular/http-auth-interceptor.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/angular/http-auth-interceptor.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/core/tutorapp.core.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/core/tutorapp.core.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/index/services/applicationdatafactory.js'; against '/assets/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/index/tutorapp.index.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/index/services/applicationDataFactory.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/index/tutorapp.index.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/core/services/domainservicefactory.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/core/services/DomainServiceFactory.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/index/controllers/indexcontroller.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/index/controllers/indexController.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/lesson/controllers/lessoncontroller.js'; against '/assets/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/lesson/tutorapp.lesson.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/lesson/controllers/lessonController.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/lesson/tutorapp.lesson.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/angular/ui-bootstrap-tpls.js'; against '/assets/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/lesson/domain/lesson.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/angular/ui-bootstrap-tpls.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/lesson/domain/Lesson.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/lesson/templates/list.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/lesson/templates/list.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/authentication/controllers/authcontroller.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/authentication/controllers/authController.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/tutorapp.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/tutorapp.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/tutorapp/authentication/tutorapp.authentication.js'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/tutorapp/authentication/tutorapp.authentication.js?compile=false has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/bootstrap/bootstrap.css.map'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/bootstrap/bootstrap.css.map has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/assets/spinner.gif'; against '/assets/**'
DEBUG org.springframework.security.web.FilterChainProxy - /assets/spinner.gif has an empty filter list
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/login'; against '/assets/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/login'; against '/**/js/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/login'; against '/**/css/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/login'; against '/**/images/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/login'; against '/**/favicon.ico'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/login'; against '/api/**'
DEBUG org.springframework.security.web.FilterChainProxy - /api/login at position 1 of 7 in additional filter chain; firing Filter: 'SecurityRequestHolderFilter'
DEBUG org.springframework.security.web.FilterChainProxy - /api/login at position 2 of 7 in additional filter chain; firing Filter: 'MutableLogoutFilter'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/login'; against '/logoff'
DEBUG org.springframework.security.web.FilterChainProxy - /api/login at position 3 of 7 in additional filter chain; firing Filter: 'RestAuthenticationFilter'
DEBUG grails.plugin.springsecurity.rest.RestAuthenticationFilter - Actual URI is /api/login; endpoint URL is /api/login
DEBUG grails.plugin.springsecurity.rest.RestAuthenticationFilter - Applying authentication filter to this request
DEBUG grails.plugin.springsecurity.rest.credentials.DefaultJsonPayloadCredentialsExtractor - Extracted credentials from JSON payload. Username: test, password: [PROTECTED]
DEBUG grails.plugin.springsecurity.rest.RestAuthenticationFilter - Trying to authenticate the request
DEBUG org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
DEBUG org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl - getReachableGrantedAuthorities() - From the roles [ROLE_USER] one can reach [ROLE_USER] in zero or more steps.
DEBUG grails.plugin.springsecurity.rest.RestAuthenticationFilter - Request authenticated. Storing the authentication result in the security context
DEBUG grails.plugin.springsecurity.rest.RestAuthenticationFilter - Authentication result: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#442bf5c6: Principal: grails.plugin.springsecurity.userdetails.GrailsUser#364492: Username: test; 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#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER
DEBUG grails.plugin.springsecurity.rest.token.generation.jwt.AbstractJwtTokenGenerator - Generating an access token with default expiration: 3600
DEBUG grails.plugin.springsecurity.rest.token.generation.jwt.AbstractJwtTokenGenerator - Serializing the principal received
DEBUG grails.plugin.springsecurity.rest.token.generation.jwt.AbstractJwtTokenGenerator - Setting expiration to 3600
DEBUG grails.plugin.springsecurity.rest.token.generation.jwt.AbstractJwtTokenGenerator - Generated claim set: {"principal":"H4sIAAAAAAAAAJVSPU8cMRCdPQ4BQiIQKUgU0ABdtCeR8qqADiS0AsRxDUhEvt1hY\/DaG9sLdw26CgoKEB8SEn+Bf5I0+QERFLTUtBkvHHtJg3Blj5\/fe\/PGt4\/QbzR8iTXjwvipyGIufZNqLmODYaa5bfuZQR2hzRFLObBBFXheXgm8AEo8svAx2GX7rCKYjCurzV0MbbWlYU7p+IVxR7MED5Te81+5Q6XxH4GC2jsrwcAmjLEwVJm0K0rWWinXGG3CaFELVLjnSp9CukFpOROmFzqAkjUFRgEMs8x+V6TK0Vj48Gw2s1xU6mirAQymzBhy918ndeusu3tnU1IHP+AQyq3Uo0XZzTqo73j8BSUEdc2VNDMNmaiI73AnTvydyfPfpzedRgmAMvn89puiPjEPnZ\/bT1N50F5oYbzHegGrtlJyM1Ywb2h0yn+u1y6uHo+3+kjZIRbfP4+Zry\/JtRdUkjLNrOqZEdEelN2eyOffJu9Ooe3XeZIKpB8lLUavEgUxtVvWSnTztjC0vhrUvjXqtXV3KluaI2mO5C27WfmBokmdPJz9Op2+o\/fL0L\/PRIaU+GgBWsmSJuqj26vJ4cv7k9x\/9y\/\/BWSQFi0PAwAA","sub":"test","roles":["ROLE_USER"],"exp":1463879104,"iat":1463875504}
DEBUG grails.plugin.springsecurity.rest.token.generation.jwt.AbstractJwtTokenGenerator - Generating access token...
DEBUG grails.plugin.springsecurity.rest.token.generation.jwt.AbstractJwtTokenGenerator - Generating refresh token...
DEBUG grails.plugin.springsecurity.rest.token.generation.jwt.AbstractJwtTokenGenerator - Setting expiration to 3600
DEBUG grails.plugin.springsecurity.rest.token.generation.jwt.AbstractJwtTokenGenerator - Generated claim set: {"principal":"H4sIAAAAAAAAAJVSPU8cMRCdPQ4BQiIQKUgU0ABdtCeR8qqADiS0AsRxDUhEvt1hY\/DaG9sLdw26CgoKEB8SEn+Bf5I0+QERFLTUtBkvHHtJg3Blj5\/fe\/PGt4\/QbzR8iTXjwvipyGIufZNqLmODYaa5bfuZQR2hzRFLObBBFXheXgm8AEo8svAx2GX7rCKYjCurzV0MbbWlYU7p+IVxR7MED5Te81+5Q6XxH4GC2jsrwcAmjLEwVJm0K0rWWinXGG3CaFELVLjnSp9CukFpOROmFzqAkjUFRgEMs8x+V6TK0Vj48Gw2s1xU6mirAQymzBhy918ndeusu3tnU1IHP+AQyq3Uo0XZzTqo73j8BSUEdc2VNDMNmaiI73AnTvydyfPfpzedRgmAMvn89puiPjEPnZ\/bT1N50F5oYbzHegGrtlJyM1Ywb2h0yn+u1y6uHo+3+kjZIRbfP4+Zry\/JtRdUkjLNrOqZEdEelN2eyOffJu9Ooe3XeZIKpB8lLUavEgUxtVvWSnTztjC0vhrUvjXqtXV3KluaI2mO5C27WfmBokmdPJz9Op2+o\/fL0L\/PRIaU+GgBWsmSJuqj26vJ4cv7k9x\/9y\/\/BWSQFi0PAwAA","sub":"test","roles":["ROLE_USER"],"exp":1463879104,"iat":1463875504}
DEBUG grails.plugin.springsecurity.rest.RestAuthenticationFilter - Generated token: grails.plugin.springsecurity.rest.token.AccessToken(accessToken:eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUFU4Y01SQ2RQUTRCUWlJUUtVZ1UwQUJkdENlUjhxcUFEaVMwQXNSeERVaEV2dDFoWVwvRGFHOXNMZHcyNkNnb0tFQjhTRW4rQmY1STArUUVSRkxUVXRCa3ZISHRKZzNCbGo1XC9mZVwvUEd0NFwvUWJ6UjhpVFhqd3ZpcHlHSXVmWk5xTG1PRFlhYTViZnVaUVIyaHpSRkxPYkJCRlhoZVhnbThBRW84c3ZBeDJHWDdyQ0tZakN1cnpWME1iYldsWVU3cCtJVnhSN01FRDVUZTgxKzVRNlh4SDRHQzJqc3J3Y0FtakxFd1ZKbTBLMHJXV2luWEdHM0NhRkVMVkxqblNwOUN1a0ZwT1JPbUZ6cUFralVGUmdFTXM4eCtWNlRLMFZqNDhHdzJzMXhVNm1pckFReW16Qmh5OTE4bmRldXN1M3RuVTFJSFArQVF5cTNVbzBYWnpUcW83M2o4QlNVRWRjMlZORE1ObWFpSTczQW5UdnlkeWZQZnB6ZWRSZ21BTXZuODlwdWlQakVQblpcL2JUMU41MEY1b1liekhlZ0dydGxKeU0xWXdiMmgweW4rdTF5NnVIbyszK2tqWklSYmZQNCtacnlcL0p0UmRVa2pMTnJPcVpFZEVlbE4yZXlPZmZKdTlPb2UzWGVaSUtwQjhsTFVhdkVnVXh0VnZXU25UenRqQzB2aHJVdmpYcXRYVjNLbHVhSTJtTzVDMjdXZm1Cb2ttZFBKejlPcDIrb1wvZkwwTFwvUFJJYVUrR2dCV3NtU0p1cWoyNnZKNGN2N2s5eFwvOXlcL1wvQldTUUZpMFBBd0FBIiwic3ViIjoidGVzdCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJleHAiOjE0NjM4NzkxMDQsImlhdCI6MTQ2Mzg3NTUwNH0.ULg0BUuC_yi44-cdU1rXAJ8ls8Btpwtuobd1mI8top8, expiration:3600, refreshToken:eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUFU4Y01SQ2RQUTRCUWlJUUtVZ1UwQUJkdENlUjhxcUFEaVMwQXNSeERVaEV2dDFoWVwvRGFHOXNMZHcyNkNnb0tFQjhTRW4rQmY1STArUUVSRkxUVXRCa3ZISHRKZzNCbGo1XC9mZVwvUEd0NFwvUWJ6UjhpVFhqd3ZpcHlHSXVmWk5xTG1PRFlhYTViZnVaUVIyaHpSRkxPYkJCRlhoZVhnbThBRW84c3ZBeDJHWDdyQ0tZakN1cnpWME1iYldsWVU3cCtJVnhSN01FRDVUZTgxKzVRNlh4SDRHQzJqc3J3Y0FtakxFd1ZKbTBLMHJXV2luWEdHM0NhRkVMVkxqblNwOUN1a0ZwT1JPbUZ6cUFralVGUmdFTXM4eCtWNlRLMFZqNDhHdzJzMXhVNm1pckFReW16Qmh5OTE4bmRldXN1M3RuVTFJSFArQVF5cTNVbzBYWnpUcW83M2o4QlNVRWRjMlZORE1ObWFpSTczQW5UdnlkeWZQZnB6ZWRSZ21BTXZuODlwdWlQakVQblpcL2JUMU41MEY1b1liekhlZ0dydGxKeU0xWXdiMmgweW4rdTF5NnVIbyszK2tqWklSYmZQNCtacnlcL0p0UmRVa2pMTnJPcVpFZEVlbE4yZXlPZmZKdTlPb2UzWGVaSUtwQjhsTFVhdkVnVXh0VnZXU25UenRqQzB2aHJVdmpYcXRYVjNLbHVhSTJtTzVDMjdXZm1Cb2ttZFBKejlPcDIrb1wvZkwwTFwvUFJJYVUrR2dCV3NtU0p1cWoyNnZKNGN2N2s5eFwvOXlcL1wvQldTUUZpMFBBd0FBIiwic3ViIjoidGVzdCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJpYXQiOjE0NjM4NzU1MDR9.cyFgeZC3mx4zfZvjKMib-zDPqSUi1hx_5MNZUWSDIX4, principal:grails.plugin.springsecurity.userdetails.GrailsUser#364492: Username: test; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER, super:grails.plugin.springsecurity.rest.token.AccessToken#442b46a2: Principal: grails.plugin.springsecurity.userdetails.GrailsUser#364492: Username: test; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER)
DEBUG grails.plugin.springsecurity.rest.token.storage.jwt.JwtTokenStorageService - Nothing to store as this is a stateless implementation
DEBUG grails.plugin.springsecurity.rest.token.rendering.DefaultAccessTokenJsonRenderer - Generated JSON:
{
"access_token": "eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUFU4Y01SQ2RQUTRCUWlJUUtVZ1UwQUJkdENlUjhxcUFEaVMwQXNSeERVaEV2dDFoWVwvRGFHOXNMZHcyNkNnb0tFQjhTRW4rQmY1STArUUVSRkxUVXRCa3ZISHRKZzNCbGo1XC9mZVwvUEd0NFwvUWJ6UjhpVFhqd3ZpcHlHSXVmWk5xTG1PRFlhYTViZnVaUVIyaHpSRkxPYkJCRlhoZVhnbThBRW84c3ZBeDJHWDdyQ0tZakN1cnpWME1iYldsWVU3cCtJVnhSN01FRDVUZTgxKzVRNlh4SDRHQzJqc3J3Y0FtakxFd1ZKbTBLMHJXV2luWEdHM0NhRkVMVkxqblNwOUN1a0ZwT1JPbUZ6cUFralVGUmdFTXM4eCtWNlRLMFZqNDhHdzJzMXhVNm1pckFReW16Qmh5OTE4bmRldXN1M3RuVTFJSFArQVF5cTNVbzBYWnpUcW83M2o4QlNVRWRjMlZORE1ObWFpSTczQW5UdnlkeWZQZnB6ZWRSZ21BTXZuODlwdWlQakVQblpcL2JUMU41MEY1b1liekhlZ0dydGxKeU0xWXdiMmgweW4rdTF5NnVIbyszK2tqWklSYmZQNCtacnlcL0p0UmRVa2pMTnJPcVpFZEVlbE4yZXlPZmZKdTlPb2UzWGVaSUtwQjhsTFVhdkVnVXh0VnZXU25UenRqQzB2aHJVdmpYcXRYVjNLbHVhSTJtTzVDMjdXZm1Cb2ttZFBKejlPcDIrb1wvZkwwTFwvUFJJYVUrR2dCV3NtU0p1cWoyNnZKNGN2N2s5eFwvOXlcL1wvQldTUUZpMFBBd0FBIiwic3ViIjoidGVzdCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJleHAiOjE0NjM4NzkxMDQsImlhdCI6MTQ2Mzg3NTUwNH0.ULg0BUuC_yi44-cdU1rXAJ8ls8Btpwtuobd1mI8top8",
"refresh_token": "eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUFU4Y01SQ2RQUTRCUWlJUUtVZ1UwQUJkdENlUjhxcUFEaVMwQXNSeERVaEV2dDFoWVwvRGFHOXNMZHcyNkNnb0tFQjhTRW4rQmY1STArUUVSRkxUVXRCa3ZISHRKZzNCbGo1XC9mZVwvUEd0NFwvUWJ6UjhpVFhqd3ZpcHlHSXVmWk5xTG1PRFlhYTViZnVaUVIyaHpSRkxPYkJCRlhoZVhnbThBRW84c3ZBeDJHWDdyQ0tZakN1cnpWME1iYldsWVU3cCtJVnhSN01FRDVUZTgxKzVRNlh4SDRHQzJqc3J3Y0FtakxFd1ZKbTBLMHJXV2luWEdHM0NhRkVMVkxqblNwOUN1a0ZwT1JPbUZ6cUFralVGUmdFTXM4eCtWNlRLMFZqNDhHdzJzMXhVNm1pckFReW16Qmh5OTE4bmRldXN1M3RuVTFJSFArQVF5cTNVbzBYWnpUcW83M2o4QlNVRWRjMlZORE1ObWFpSTczQW5UdnlkeWZQZnB6ZWRSZ21BTXZuODlwdWlQakVQblpcL2JUMU41MEY1b1liekhlZ0dydGxKeU0xWXdiMmgweW4rdTF5NnVIbyszK2tqWklSYmZQNCtacnlcL0p0UmRVa2pMTnJPcVpFZEVlbE4yZXlPZmZKdTlPb2UzWGVaSUtwQjhsTFVhdkVnVXh0VnZXU25UenRqQzB2aHJVdmpYcXRYVjNLbHVhSTJtTzVDMjdXZm1Cb2ttZFBKejlPcDIrb1wvZkwwTFwvUFJJYVUrR2dCV3NtU0p1cWoyNnZKNGN2N2s5eFwvOXlcL1wvQldTUUZpMFBBd0FBIiwic3ViIjoidGVzdCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJpYXQiOjE0NjM4NzU1MDR9.cyFgeZC3mx4zfZvjKMib-zDPqSUi1hx_5MNZUWSDIX4",
"roles": ["ROLE_USER"],
"token_type": "Bearer",
"expires_in": 3600,
"username": "test"
}
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/lessons'; against '/assets/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/lessons'; against '/**/js/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/lessons'; against '/**/css/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/lessons'; against '/**/images/**'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/lessons'; against '/**/favicon.ico'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/lessons'; against '/api/**'
DEBUG org.springframework.security.web.FilterChainProxy - /api/lessons at position 1 of 7 in additional filter chain; firing Filter: 'SecurityRequestHolderFilter'
DEBUG org.springframework.security.web.FilterChainProxy - /api/lessons at position 2 of 7 in additional filter chain; firing Filter: 'MutableLogoutFilter'
DEBUG org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/api/lessons'; against '/logoff'
DEBUG org.springframework.security.web.FilterChainProxy - /api/lessons at position 3 of 7 in additional filter chain; firing Filter: 'RestAuthenticationFilter'
DEBUG grails.plugin.springsecurity.rest.RestAuthenticationFilter - Actual URI is /api/lessons; endpoint URL is /api/login
DEBUG org.springframework.security.web.FilterChainProxy - /api/lessons at position 4 of 7 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG org.springframework.security.web.FilterChainProxy - /api/lessons at position 5 of 7 in additional filter chain; firing Filter: 'RestTokenValidationFilter'
DEBUG grails.plugin.springsecurity.rest.token.bearer.BearerTokenReader - Looking for bearer token in Authorization header, query string or Form-Encoded body parameter
DEBUG grails.plugin.springsecurity.rest.token.bearer.BearerTokenReader - Found bearer token in Authorization header
DEBUG grails.plugin.springsecurity.rest.token.bearer.BearerTokenReader - Token: eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUFU4Y01SQ2RQUTRCUWlJUUtVZ1UwQUJkdENlUjhxcUFEaVMwQXNSeERVaEV2dDFoWVwvRGFHOXNMZHcyNkNnb0tFQjhTRW4rQmY1STArUUVSRkxUVXRCa3ZISHRKZzNCbGo1XC9mZVwvUEd0NFwvUWJ6UjhpVFhqd3ZpcHlHSXVmWk5xTG1PRFlhYTViZnVaUVIyaHpSRkxPYkJCRlhoZVhnbThBRW84c3ZBeDJHWDdyQ0tZakN1cnpWME1iYldsWVU3cCtJVnhSN01FRDVUZTgxKzVRNlh4SDRHQzJqc3J3Y0FtakxFd1ZKbTBLMHJXV2luWEdHM0NhRkVMVkxqblNwOUN1a0ZwT1JPbUZ6cUFralVGUmdFTXM4eCtWNlRLMFZqNDhHdzJzMXhVNm1pckFReW16Qmh5OTE4bmRldXN1M3RuVTFJSFArQVF5cTNVbzBYWnpUcW83M2o4QlNVRWRjMlZORE1ObWFpSTczQW5UdnlkeWZQZnB6ZWRSZ21BTXZuODlwdWlQakVQblpcL2JUMU41MEY1b1liekhlZ0dydGxKeU0xWXdiMmgweW4rdTF5NnVIbyszK2tqWklSYmZQNCtacnlcL0p0UmRVa2pMTnJPcVpFZEVlbE4yZXlPZmZKdTlPb2UzWGVaSUtwQjhsTFVhdkVnVXh0VnZXU25UenRqQzB2aHJVdmpYcXRYVjNLbHVhSTJtTzVDMjdXZm1Cb2ttZFBKejlPcDIrb1wvZkwwTFwvUFJJYVUrR2dCV3NtU0p1cWoyNnZKNGN2N2s5eFwvOXlcL1wvQldTUUZpMFBBd0FBIiwic3ViIjoidGVzdCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJleHAiOjE0NjM4MjUwNzQsImlhdCI6MTQ2MzgyMTQ3NH0.QfbJEHCAqifsmfmw5_a0AeI-KOexk7Hpv1QzIF5BrHs
DEBUG grails.plugin.springsecurity.rest.RestTokenValidationFilter - Token found: eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUFU4Y01SQ2RQUTRCUWlJUUtVZ1UwQUJkdENlUjhxcUFEaVMwQXNSeERVaEV2dDFoWVwvRGFHOXNMZHcyNkNnb0tFQjhTRW4rQmY1STArUUVSRkxUVXRCa3ZISHRKZzNCbGo1XC9mZVwvUEd0NFwvUWJ6UjhpVFhqd3ZpcHlHSXVmWk5xTG1PRFlhYTViZnVaUVIyaHpSRkxPYkJCRlhoZVhnbThBRW84c3ZBeDJHWDdyQ0tZakN1cnpWME1iYldsWVU3cCtJVnhSN01FRDVUZTgxKzVRNlh4SDRHQzJqc3J3Y0FtakxFd1ZKbTBLMHJXV2luWEdHM0NhRkVMVkxqblNwOUN1a0ZwT1JPbUZ6cUFralVGUmdFTXM4eCtWNlRLMFZqNDhHdzJzMXhVNm1pckFReW16Qmh5OTE4bmRldXN1M3RuVTFJSFArQVF5cTNVbzBYWnpUcW83M2o4QlNVRWRjMlZORE1ObWFpSTczQW5UdnlkeWZQZnB6ZWRSZ21BTXZuODlwdWlQakVQblpcL2JUMU41MEY1b1liekhlZ0dydGxKeU0xWXdiMmgweW4rdTF5NnVIbyszK2tqWklSYmZQNCtacnlcL0p0UmRVa2pMTnJPcVpFZEVlbE4yZXlPZmZKdTlPb2UzWGVaSUtwQjhsTFVhdkVnVXh0VnZXU25UenRqQzB2aHJVdmpYcXRYVjNLbHVhSTJtTzVDMjdXZm1Cb2ttZFBKejlPcDIrb1wvZkwwTFwvUFJJYVUrR2dCV3NtU0p1cWoyNnZKNGN2N2s5eFwvOXlcL1wvQldTUUZpMFBBd0FBIiwic3ViIjoidGVzdCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJleHAiOjE0NjM4MjUwNzQsImlhdCI6MTQ2MzgyMTQ3NH0.QfbJEHCAqifsmfmw5_a0AeI-KOexk7Hpv1QzIF5BrHs
DEBUG grails.plugin.springsecurity.rest.RestTokenValidationFilter - Trying to authenticate the token
DEBUG grails.plugin.springsecurity.rest.RestAuthenticationProvider - Use JWT: true
DEBUG grails.plugin.springsecurity.rest.RestAuthenticationProvider - Trying to validate token eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUFU4Y01SQ2RQUTRCUWlJUUtVZ1UwQUJkdENlUjhxcUFEaVMwQXNSeERVaEV2dDFoWVwvRGFHOXNMZHcyNkNnb0tFQjhTRW4rQmY1STArUUVSRkxUVXRCa3ZISHRKZzNCbGo1XC9mZVwvUEd0NFwvUWJ6UjhpVFhqd3ZpcHlHSXVmWk5xTG1PRFlhYTViZnVaUVIyaHpSRkxPYkJCRlhoZVhnbThBRW84c3ZBeDJHWDdyQ0tZakN1cnpWME1iYldsWVU3cCtJVnhSN01FRDVUZTgxKzVRNlh4SDRHQzJqc3J3Y0FtakxFd1ZKbTBLMHJXV2luWEdHM0NhRkVMVkxqblNwOUN1a0ZwT1JPbUZ6cUFralVGUmdFTXM4eCtWNlRLMFZqNDhHdzJzMXhVNm1pckFReW16Qmh5OTE4bmRldXN1M3RuVTFJSFArQVF5cTNVbzBYWnpUcW83M2o4QlNVRWRjMlZORE1ObWFpSTczQW5UdnlkeWZQZnB6ZWRSZ21BTXZuODlwdWlQakVQblpcL2JUMU41MEY1b1liekhlZ0dydGxKeU0xWXdiMmgweW4rdTF5NnVIbyszK2tqWklSYmZQNCtacnlcL0p0UmRVa2pMTnJPcVpFZEVlbE4yZXlPZmZKdTlPb2UzWGVaSUtwQjhsTFVhdkVnVXh0VnZXU25UenRqQzB2aHJVdmpYcXRYVjNLbHVhSTJtTzVDMjdXZm1Cb2ttZFBKejlPcDIrb1wvZkwwTFwvUFJJYVUrR2dCV3NtU0p1cWoyNnZKNGN2N2s5eFwvOXlcL1wvQldTUUZpMFBBd0FBIiwic3ViIjoidGVzdCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJleHAiOjE0NjM4MjUwNzQsImlhdCI6MTQ2MzgyMTQ3NH0.QfbJEHCAqifsmfmw5_a0AeI-KOexk7Hpv1QzIF5BrHs
DEBUG grails.plugin.springsecurity.rest.RestTokenValidationFilter - Authentication failed: Token eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUFU4Y01SQ2RQUTRCUWlJUUtVZ1UwQUJkdENlUjhxcUFEaVMwQXNSeERVaEV2dDFoWVwvRGFHOXNMZHcyNkNnb0tFQjhTRW4rQmY1STArUUVSRkxUVXRCa3ZISHRKZzNCbGo1XC9mZVwvUEd0NFwvUWJ6UjhpVFhqd3ZpcHlHSXVmWk5xTG1PRFlhYTViZnVaUVIyaHpSRkxPYkJCRlhoZVhnbThBRW84c3ZBeDJHWDdyQ0tZakN1cnpWME1iYldsWVU3cCtJVnhSN01FRDVUZTgxKzVRNlh4SDRHQzJqc3J3Y0FtakxFd1ZKbTBLMHJXV2luWEdHM0NhRkVMVkxqblNwOUN1a0ZwT1JPbUZ6cUFralVGUmdFTXM4eCtWNlRLMFZqNDhHdzJzMXhVNm1pckFReW16Qmh5OTE4bmRldXN1M3RuVTFJSFArQVF5cTNVbzBYWnpUcW83M2o4QlNVRWRjMlZORE1ObWFpSTczQW5UdnlkeWZQZnB6ZWRSZ21BTXZuODlwdWlQakVQblpcL2JUMU41MEY1b1liekhlZ0dydGxKeU0xWXdiMmgweW4rdTF5NnVIbyszK2tqWklSYmZQNCtacnlcL0p0UmRVa2pMTnJPcVpFZEVlbE4yZXlPZmZKdTlPb2UzWGVaSUtwQjhsTFVhdkVnVXh0VnZXU25UenRqQzB2aHJVdmpYcXRYVjNLbHVhSTJtTzVDMjdXZm1Cb2ttZFBKejlPcDIrb1wvZkwwTFwvUFJJYVUrR2dCV3NtU0p1cWoyNnZKNGN2N2s5eFwvOXlcL1wvQldTUUZpMFBBd0FBIiwic3ViIjoidGVzdCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJleHAiOjE0NjM4MjUwNzQsImlhdCI6MTQ2MzgyMTQ3NH0.QfbJEHCAqifsmfmw5_a0AeI-KOexk7Hpv1QzIF5BrHs has expired
DEBUG grails.plugin.springsecurity.rest.token.bearer.BearerTokenReader - Looking for bearer token in Authorization header, query string or Form-Encoded body parameter
DEBUG grails.plugin.springsecurity.rest.token.bearer.BearerTokenReader - Found bearer token in Authorization header
DEBUG grails.plugin.springsecurity.rest.token.bearer.BearerTokenReader - Token: eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUFU4Y01SQ2RQUTRCUWlJUUtVZ1UwQUJkdENlUjhxcUFEaVMwQXNSeERVaEV2dDFoWVwvRGFHOXNMZHcyNkNnb0tFQjhTRW4rQmY1STArUUVSRkxUVXRCa3ZISHRKZzNCbGo1XC9mZVwvUEd0NFwvUWJ6UjhpVFhqd3ZpcHlHSXVmWk5xTG1PRFlhYTViZnVaUVIyaHpSRkxPYkJCRlhoZVhnbThBRW84c3ZBeDJHWDdyQ0tZakN1cnpWME1iYldsWVU3cCtJVnhSN01FRDVUZTgxKzVRNlh4SDRHQzJqc3J3Y0FtakxFd1ZKbTBLMHJXV2luWEdHM0NhRkVMVkxqblNwOUN1a0ZwT1JPbUZ6cUFralVGUmdFTXM4eCtWNlRLMFZqNDhHdzJzMXhVNm1pckFReW16Qmh5OTE4bmRldXN1M3RuVTFJSFArQVF5cTNVbzBYWnpUcW83M2o4QlNVRWRjMlZORE1ObWFpSTczQW5UdnlkeWZQZnB6ZWRSZ21BTXZuODlwdWlQakVQblpcL2JUMU41MEY1b1liekhlZ0dydGxKeU0xWXdiMmgweW4rdTF5NnVIbyszK2tqWklSYmZQNCtacnlcL0p0UmRVa2pMTnJPcVpFZEVlbE4yZXlPZmZKdTlPb2UzWGVaSUtwQjhsTFVhdkVnVXh0VnZXU25UenRqQzB2aHJVdmpYcXRYVjNLbHVhSTJtTzVDMjdXZm1Cb2ttZFBKejlPcDIrb1wvZkwwTFwvUFJJYVUrR2dCV3NtU0p1cWoyNnZKNGN2N2s5eFwvOXlcL1wvQldTUUZpMFBBd0FBIiwic3ViIjoidGVzdCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJleHAiOjE0NjM4MjUwNzQsImlhdCI6MTQ2MzgyMTQ3NH0.QfbJEHCAqifsmfmw5_a0AeI-KOexk7Hpv1QzIF5BrHs
DEBUG grails.plugin.springsecurity.rest.token.bearer.BearerTokenAuthenticationFailureHandler - Sending status code 401 and header WWW-Authenticate: Bearer error="invalid_token"
My angularJS code was not updating the localStorage correctly. So it was always attaching the wrong token on requests. Fixed.
I've been using a Grails Oauth Plugin for LinkedIn authentication for a few months now without any issues; today we are seeing this error with no change to our existing codebase. I verified that the API keys and the scope were correct on the LinkedIn Developer site. Anyone know how to solve this issue?
Error
response status code: 403
response body: oauth_problem=Scope%20INVALID%20%3A%20r_contactinfo%2Br_basicprofile%2Br_emailaddress
This is a version of the request that is being sent by the Scribe lib:
using base64 encoder: CommonsCodec
base string is: POST&https%3A%2F%2Fapi.linkedin.com%2Fuas%2Foauth%2FrequestToken&oauth_callback%3Dhttps%253A%252F%252Flocalhost%253A8443%252Foauth%252Flinkedin%252Fcallback%26oauth_consumer_key%3Dxxxxxxxxxxxxx%26oauth_nonce%3Dxxxxxxxxxxxxxxxxx%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1431479305%26oauth_version%3D1.0%26scope%3Dr_contactinfo%252Br_basicprofile%252Br_emailaddress
signature is: xxxxxxxxxxxxxxxxxxxxxxx
appended additional OAuth parameters: { oauth_callback -> https://localhost:8443/oauth/linkedin/callback , oauth_signature -> xxxxxxxxxxxxxxxxxxxxxxxxxxx, scope -> r_contactinfo+r_basicprofile+r_emailaddress , oauth_version -> 1.0 , oauth_nonce -> xxxxxxxxxxx , oauth_signature_method -> HMAC-SHA1 , oauth_consumer_key -> xxxxxxxxxxxxxxxxxx , oauth_timestamp -> 1431479305 }
using Http Header signature
Linked has changed their API usage terms with special permission needed for "r_contactinfo"
See
https://developer.linkedin.com/support/developer-program-transition
And
https://developer.linkedin.com/support/developer-program-transition
So if your Oauth request required r_contactinfo previously you are going to see this error. The fix is to not request r_contactinfo unless you have the specific permission from Li - uncheck this on Li Developer Dashboard for your application.
r_basicprofile & r_emailaddress can still be retrieved.
I have an error with Cas when i try login, the logs fron the error are the next, i've self signed certificate and already add these to my keystore and and the keystore to the cacerts
thx for the help
These is the log from CAS
ServiceValidateController [ERROR] TicketException generating ticket for: [callbackUrl: https://localhost:8443/receptor]
org.jasig.cas.ticket.TicketCreationException: error.authentication.credentials.bad
at org.jasig.cas.CentralAuthenticationServiceImpl.delegateTicketGrantingTicket(CentralAuthenticationServiceImpl.java:291)
at org.jasig.cas.web.ServiceValidateController.handleRequestInternal(ServiceValidateController.java:126)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.jasig.cas.web.init.SafeDispatcherServlet.service(SafeDispatcherServlet.java:115)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.inspektr.common.web.ClientInfoThreadLocalFilter.doFilterInternal(ClientInfoThreadLocalFilter.java:48)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:722)
Caused by: error.authentication.credentials.bad
at org.jasig.cas.authentication.handler.BadCredentialsAuthenticationException.<clinit>(BadCredentialsAuthenticationException.java:25)
at org.jasig.cas.authentication.AuthenticationManagerImpl.authenticate(AuthenticationManagerImpl.java:113)
at org.jasig.cas.CentralAuthenticationServiceImpl.delegateTicketGrantingTicket(CentralAuthenticationServiceImpl.java:262)
... 26 more
These is the log from Ldap
geobolivia slapd[3024]: conn=1003 op=3 SRCH base="ou=users,dc=geobolivia,dc=gob,dc=bo" scope=2 deref=3 filter="(uid=geobolivia)"
geobolivia slapd[3024]: conn=1003 op=3 SEARCH RESULT tag=101 err=0 nentries=0 text=
geobolivia slapd[3024]: conn=1003 op=4 SRCH base="ou=users,dc=geobolivia,dc=gob,dc=bo" scope=2 deref=3 filter="(uid=_cas_stateful_)"
geobolivia slapd[3024]: conn=1003 op=4 SEARCH RESULT tag=101 err=0 nentries=0 text=
And these is the log from Security-proxy
ProxyGrantingTicketStorageImpl [INFO] No Proxy Ticket found for
FilterBasedLdapUserSearch [DEBUG] Searching for user 'geobolivia', with user search [ searchFilter: '(uid={0})', searchBase: 'ou=users', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ]
AbstractContextSource [DEBUG] Got Ldap context on server 'ldap://localhost:389/dc=geobolivia,dc=gob,dc=bo'
SpringSecurityLdapTemplate [DEBUG] Searching for entry in under DN 'dc=geobolivia,dc=gob,dc=bo', base = 'ou=users', filter = '(uid={0})'
ProviderManager [DEBUG] Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider
LdapAuthenticationProvider [DEBUG] Processing authentication request for user: _cas_stateful_
FilterBasedLdapUserSearch [DEBUG] Searching for user '_cas_stateful_', with user search [ searchFilter: '(uid={0})', searchBase: 'ou=users', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ]
AbstractContextSource [DEBUG] Got Ldap context on server 'ldap://localhost:389/dc=geobolivia,dc=gob,dc=bo'
SpringSecurityLdapTemplate [DEBUG] Searching for entry in under DN 'dc=geobolivia,dc=gob,dc=bo', base = 'ou=users', filter = '(uid={0})'
2013-08-29 18:29:15 CasAuthenticationFilter [DEBUG] Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2013-08-29 18:29:15 CasAuthenticationFilter [DEBUG] Updated SecurityContextHolder to contain null Authentication
CasAuthenticationFilter [DEBUG] Delegating to authentication failure handlerorg.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler#1e6ba8ee
SimpleUrlAuthenticationFailureHandler [DEBUG] No failure URL set, sending 401 Unauthorized error
HttpSessionSecurityContextRepository [DEBUG] SecurityContext is empty or anonymous - context will not be stored in HttpSession.
SecurityContextPersistenceFilter [DEBUG] SecurityContextHolder now cleared, as request processing completed
This is very similar to: CAS credentials bad
Basically CAS is trying to call the client app because it is trying to deliver a PGT, but the client app isn't answering on the callback url.
I am trying to implement Google Login for my webapp Using OAuth 2.0 for Login. However, while performing the step 4 ie. "Exchange Code for Access Token and ID Token", when I perform a POST request for the access and ID token, I get the following exception along with the below stacktrace.
java.net.UnknownHostException: https://accounts.google.com/o/oauth2/token
at java.net.Inet4AddressImpl.lookupAllHostAddr(Native Method)
at java.net.InetAddress$1.lookupAllHostAddr(InetAddress.java:866)
at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1258)
at java.net.InetAddress.getAllByName0(InetAddress.java:1211)
at java.net.InetAddress.getAllByName(InetAddress.java:1127)
at java.net.InetAddress.getAllByName(InetAddress.java:1063)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.resolveHostname(DefaultClientConnectionOperator.java:242)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:130)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:150)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:575)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:776)
at dispatch.classic.BlockingHttp$class.dispatch$classic$BlockingHttp$$execute(Http.scala:45)
at dispatch.classic.BlockingHttp$$anonfun$execute$1$$anonfun$apply$3.apply(Http.scala:58)
at dispatch.classic.BlockingHttp$$anonfun$execute$1$$anonfun$apply$3.apply(Http.scala:58)
at scala.Option.getOrElse(Option.scala:120)
at dispatch.classic.BlockingHttp$$anonfun$execute$1.apply(Http.scala:58)
at dispatch.classic.Http.pack(Http.scala:25)
at dispatch.classic.BlockingHttp$class.execute(Http.scala:53)
at dispatch.classic.Http.execute(Http.scala:21)
at dispatch.classic.HttpExecutor$class.x(executor.scala:36)
at dispatch.classic.Http.x(Http.scala:21)
at dispatch.classic.HttpExecutor$class.when(executor.scala:50)
at dispatch.classic.Http.when(Http.scala:21)
at dispatch.classic.HttpExecutor$class.apply(executor.scala:60)
at dispatch.classic.Http.apply(Http.scala:21)
Following are the details of the POST request:
import dispatch.classic._
val req = :/("https://accounts.google.com/o/oauth2/token").secure
val params = Map(
"code" -> code,
"client_id" -> googleClientId,
"client_secret" -> googleClientSecret,
"redirect_uri" -> googleAuthURI,
"grant_type" -> "authorization_code"
)
val res = parse(h(req << params as_str))
where,
code is the auth code returned in the pervious request to https://accounts.google.com/o/oauth2/auth [Step 2 over here ]
googleAuthURI is "https://localhost/portal/google/login" which is what I have specified in the Google API developer console.
Also I am using scala and dispatch to implement this.
Turns out it was a problem with how dispatch finds out the hostname from the request url. In this case
val req = :/("https://accounts.google.com/o/oauth2/token").secure
Dispatch interprets the hostname as "https://accounts.google.com/o/oauth2/token" which is not available and hence it throws an exception. To counter this we need to structure the req url as,
val req = :/("accounts.google.com"/"o"/"oauth2"/"token").secure