Hi I am trying to setup an OAuth provider using this documentation from grails: Grails Documentation
I have done all the steps but when I try to do a request in postman I always got a 404 not found. I have tried many configs and I also tried some different filterChain.chainMap
I also have a MobileController that works fine that I can access in the project. I have tried to copy and paste the filterchain filters to make it the same as on /mobile/ But it still gave me a 404, I have ran the init script (s2-init-oauth2-provider) to make the domain classes
Here is my code that matters for the OAuth provider:
grails-app/conf/application.groovy:
List<String> url_public = [
'/mobile/**',
'/oauth/token'
]
grails.plugin.springsecurity.filterChain.chainMap = [
[pattern: '/oauth/token', filters: 'JOINED_FILTERS,-oauth2ProviderFilter,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-exceptionTranslationFilter'],
[pattern: '/mobile/**', filters: 'JOINED_FILTERS, -securityContextPersistenceFilter, -logoutFilter, -authenticationProcessingFilter, -rememberMeAuthenticationFilter, -oauth2BasicAuthenticationFilter, -exceptionTranslationFilter'],
[pattern: '/**', filters: 'JOINED_FILTERS, -basicAuthenticationFilter, -basicExceptionTranslationFilter, -statelessSecurityContextPersistenceFilter, -oauth2ProviderFilter, -clientCredentialsTokenEndpointFilter, -oauth2BasicAuthenticationFilter, -oauth2ExceptionTranslationFilter'],
]
grails.plugin.springsecurity.oauthProvider.clientLookup.className = 'com.app.oauth.OAuthClient'
grails.plugin.springsecurity.oauthProvider.authorizationCodeLookup.className = 'com.app.oauth.AuthorizationCode'
grails.plugin.springsecurity.oauthProvider.accessTokenLookup.className = 'com.app.oauth.AccessToken'
grails.plugin.springsecurity.oauthProvider.refreshTokenLookup.className = 'com.app.oauth.RefreshToken'
grails-app/init/Bootstrap.groovy:
new OAuthClient(
clientId: 'client_id',
authorizedGrantTypes: ['authorization_code', 'refresh_token', 'implicit', 'password', 'client_credentials'],
authorities: ['ROLE_client'],
scopes: ['read', 'write'],
).save(flush: true)
println "End bootstrap.init "
The fix was that I had to remove the url from the url_public list.
List<String> url_public = [
'/mobile/**'
]
Related
I've got a Grails 2.5 application that i'm trying to upgrade to 3.3 using Spring Security Core plugin (3.2.0.M1) with the preauth setup using Siteminder. In my UserDetailsService I get the Session like this:
UserDetails loadUserByUsername(String userId, boolean loadRoles) throws UsernameNotFoundException, DataAccessException {
org.grails.web.util.WebUtils.retrieveGrailsWebRequest().getCurrentRequest().getSession()
I need to get more than the single header passed into the app and when running the app locally this works as expected but when running through a war, on weblogic 12.2.1, I get this error:
No thread-bound request found: Are you referring to request attributes outside of an
actual web request, or processing a request outside of the originally receiving thread?
If you are actually operating within a web request and still receive this message, your code
is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use
RequestContextListener or RequestContextFilter to expose the current request.
I have also tried:
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
but ran into a NPE on getRequest(). When running in Grails 2.5 with Spring Sec Core plugin 2.0-RC6, the RequestContextHolder way worked correctly. Is there a different way to grab the headers maybe? Or is it possible some property I pulled over from my previous Config.groovy file into application.groovy may have caused a problem?
resources.groovy:
beans = {
userDetailsService(com.myapp.security.MyUserDetailsService)
userDetailsServiceWrapper(org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper) {
userDetailsService = ref('userDetailsService')
}
preauthAuthProvider(org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider) {
preAuthenticatedUserDetailsService = ref('userDetailsServiceWrapper')
}
requestHeaderAuthenticationFilter(org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter){
principalRequestHeader='smauthid'
checkForPrincipalChanges = false
invalidateSessionOnPrincipalChange = false
continueFilterChainOnUnsuccessfulAuthentication = true
authenticationManager = ref('authenticationManager')
}
}
Bootstrap.groovy
SpringSecurityUtils.clientRegisterFilter('requestHeaderAuthenticationFilter', SecurityFilterPosition.PRE_AUTH_FILTER)
application.groovy
grails.plugin.springsecurity.filterChain.chainMap = [
[pattern: '/assets/**', filters: 'none'],
[pattern: '/**/js/**', filters: 'none'],
[pattern: '/**/css/**', filters: 'none'],
[pattern: '/**/images/**', filters: 'none'],
[pattern: '/**/favicon.ico', filters: 'none'],
[pattern: '/index/nouser', filters: 'none'],
[pattern: '/nouser', filters: 'none'],
[pattern: '/**', filters: 'JOINED_FILTERS']
]
grails.plugin.springsecurity.providerNames = ['preauthAuthProvider']
I am not sure if there is any difference in getting Session in UserDetailsService but I get my session by:
session["task"]=object
You can read more about session right here: Grails 3 latest Session documentation.
EDIT 1
def show(Project project) {
respond project
def object = project //params of the Task "task"
session["task"]=object
}
Iam using spring-security-core 3.1.1 in my grails 3.2.7 application. I just want to access my projectconfiguration.gsp, for this I added the following mapping in UrlMapping
"/confproject"(view: '/project/projectconfiguration')
But it is showing as You are not authorized to access this page
I know this is happened because of i did not specify any access rules for this URL. So i added the following line in the application.groovy
grails.plugin.springsecurity.controllerAnnotations.staticRules = [ [pattern: '/confproject', access: ['ROLE_ADMIN']] ]
But still iam facing the unauthorized access message.
Why the above access rule is note working?
I know that if I access the GSP through a controller and give the #Secured annotation to that controller will work fine.
But is that the only way?
Note: I don't want to use the interceptUrlMap method.
This is working for me.
UrlMappings.groovy
"/newsletter"(view: "/pages/newsletter")
application.groovy
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
...
[pattern: '/pages/**', access: ['permitAll']],
...
]
Created a new app, added compile 'org.grails.plugins:spring-security-core:3.1.2' and did:
grails s2-quickstart com.cabolabs.security User Role RequestMap
Then grails run-app.
Trying to access the /dbconsole, redirects to /login/auth
/login/auth got "localhost redirected you too many times." ERR_TOO_MANY_REDIRECTS
Is this the expected behavior or a bug form the plugin?
The doc, on the install and configuration section, doesn't mention anything about this https://grails-plugins.github.io/grails-spring-security-core/v3/#configuration
UPDATE
Found on the documentation, section 5.3 (https://grails-plugins.github.io/grails-spring-security-core/v3/) the initial RequestMap that should be added.
for (String url in [
'/', '/error', '/index', '/index.gsp', '/**/favicon.ico', '/shutdown',
'/**/js/**', '/**/css/**', '/**/images/**',
'/login', '/login.*', '/login/*',
'/logout', '/logout.*', '/logout/*']) {
new Requestmap(url: url, configAttribute: 'permitAll').save()
}
Used that in the Bootstrap.groovy, and still got the "too many redirects".
Also, can't view the /dbconsole to check the database because it's blocked by the plugin.
The solution proposed on GitHub and I tested it to work is to call clearCachedRequestmaps after creating the request map instances.
for (String url in [
'/', '/error', '/index', '/index.gsp', '/**/favicon.ico', '/shutdown',
'/**/js/**', '/**/css/**', '/**/images/**',
'/login', '/login.*', '/login/*',
'/logout', '/logout.*', '/logout/*']) {
new RequestMap(url: url, configAttribute: 'permitAll').save()
}
springSecurityService.clearCachedRequestmaps()
Little late but I just ran into the same issue. The way I fixed it was to add the following element to the chainMap:
[pattern: "/login/**", filters:"none"]
The reason why this worked is because spring was trying to get you to login before accessing the login page, which obviously wont work. The line above tells spring to allow traffic to the login endpoint without logging in first (since you can't).
I am trying to convey that the authentication/security scheme requires setting a header as follows:
Authorization: Bearer <token>
This is what I have based on the swagger documentation:
securityDefinitions:
APIKey:
type: apiKey
name: Authorization
in: header
security:
- APIKey: []
Maybe this can help:
swagger: '2.0'
info:
version: 1.0.0
title: Bearer auth example
description: >
An example for how to use Bearer Auth with OpenAPI / Swagger 2.0.
host: basic-auth-server.herokuapp.com
schemes:
- http
- https
securityDefinitions:
Bearer:
type: apiKey
name: Authorization
in: header
description: >-
Enter the token with the `Bearer: ` prefix, e.g. "Bearer abcde12345".
paths:
/:
get:
security:
- Bearer: []
responses:
'200':
description: 'Will send `Authenticated`'
'403':
description: 'You do not have necessary permissions for the resource'
You can copy&paste it to https://editor.swagger.io to check out the results.
There are also several examples in the Swagger Editor web with more complex security configurations which could help you.
Important: In this example, API consumers must include the "Bearer" prefix as part of the token value. For example, when using Swagger UI's "Authorize" dialog, you need to enter Bearer your_token instead of just your_token.
Bearer authentication in OpenAPI 3.0.0
OpenAPI 3.0 now supports Bearer/JWT authentication natively. It's defined like this:
openapi: 3.0.0
...
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT # optional, for documentation purposes only
security:
- bearerAuth: []
This is supported in Swagger UI 3.4.0+ and Swagger Editor 3.1.12+ (again, for OpenAPI 3.0 specs only!).
UI will display the "Authorize" button, which you can click and enter the bearer token (just the token itself, without the "Bearer " prefix). After that, "try it out" requests will be sent with the Authorization: Bearer xxxxxx header.
Adding Authorization header programmatically (Swagger UI 3.x)
If you use Swagger UI and, for some reason, need to add the Authorization header programmatically instead of having the users click "Authorize" and enter the token, you can use the requestInterceptor. This solution is for Swagger UI 3.x; UI 2.x used a different technique.
// index.html
const ui = SwaggerUIBundle({
url: "http://your.server.com/swagger.json",
...
requestInterceptor: (req) => {
req.headers.Authorization = "Bearer xxxxxxx"
return req
}
})
Posting 2023 answer in JSON using openapi 3.0.0:
{
"openapi": "3.0.0",
...
"servers": [
{
"url": "/"
}
],
...
"paths": {
"/skills": {
"put": {
"security": [
{
"bearerAuth": []
}
],
...
},
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
}
}
}
}
Why "Accepted Answer" works... but it wasn't enough for me
This works in the specification. At least swagger-tools (version 0.10.1) validates it as a valid.
But if you are using other tools like swagger-codegen (version 2.1.6) you will find some difficulties, even if the client generated contains the Authentication definition, like this:
this.authentications = {
'Bearer': {type: 'apiKey', 'in': 'header', name: 'Authorization'}
};
There is no way to pass the token into the header before method(endpoint) is called. Look into this function signature:
this.rootGet = function(callback) { ... }
This means that, I only pass the callback (in other cases query parameters, etc) without a token, which leads to a incorrect build of the request to server.
My alternative
Unfortunately, it's not "pretty" but it works until I get JWT Tokens support on Swagger.
Note: which is being discussed in
security: add support for Authorization header with Bearer
authentication scheme #583
Extensibility of security
definitions? #460
So, it's handle authentication like a standard header. On path object append an header paremeter:
swagger: '2.0'
info:
version: 1.0.0
title: Based on "Basic Auth Example"
description: >
An example for how to use Auth with Swagger.
host: localhost
schemes:
- http
- https
paths:
/:
get:
parameters:
-
name: authorization
in: header
type: string
required: true
responses:
'200':
description: 'Will send `Authenticated`'
'403':
description: 'You do not have necessary permissions for the resource'
This will generate a client with a new parameter on method signature:
this.rootGet = function(authorization, callback) {
// ...
var headerParams = {
'authorization': authorization
};
// ...
}
To use this method in the right way, just pass the "full string"
// 'token' and 'cb' comes from elsewhere
var header = 'Bearer ' + token;
sdk.rootGet(header, cb);
And works.
By using requestInterceptor, it worked for me:
const ui = SwaggerUIBundle({
...
requestInterceptor: (req) => {
req.headers.Authorization = "Bearer " + req.headers.Authorization;
return req;
},
...
});
My Hackie way to solve this was by modifying the swagger.go file in the echo-swagger package in my case:
At the bottom of the file update the window.onload function to include a requestInterceptor which correctly formats the token.
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "{{.URL}}",
dom_id: '#swagger-ui',
validatorUrl: null,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
,
layout: "StandaloneLayout",
requestInterceptor: (req) => {
req.headers.Authorization = "Bearer " + req.headers.Authorization
return req
}
})
window.ui = ui
}
Solving this from laravel 7x ("openapi": "3.0.0"), edit your config\l5-swagger.php with the following codes
'securityDefinitions' => [
'securitySchemes' => [
'bearerAuth' => [
'type' => 'http',
'scheme' => 'bearer',
'bearerFormat' => 'JWT',
],
],
then you can add this as a security annotation for your endpoint:
*security={
*{
*"bearerAuth": {}},
*},
We are using Spring Security plugin version 1.2.7.3 with Grails 2.2.1.
In my Config.groovy, I do:
grails.plugins.springsecurity.auth.ajaxLoginFormUrl = "/mylogin/authAjax"
thinking that, when there is an Ajax request, Spring Security will invoke authAjax() in MyloginController if the User's HttpSession has timed out.
As per doc, I ensure that the header X-Requested-With with value XMLHttpRequest is in the Ajax request so the plugin knows it is an Ajax request.
My expectation is authAjax() will be invoked and I can make that return a 401, so the UI knows it needs to pop up another login screen.
However, instead of the authAjax() getting invoked, a 302 is returned to the UI with the location field set to http://localhost:8080/MyApplication/mycontroller/authAjax
This means I'll have to put in something very hackey on my UI, check for a 302 and check the location field and then make the User re-login. I would much prefer to have a 401 returned.
Any ideas what I am doing wrong?
Thanks a million.
If anyone else has this issue, I found it was simply down to the chainMap rules.
I have my REST api sitting under the '/api/' url so my chainMap looks like this:
grails.plugin.springsecurity.filterChain.chainMap = [
[pattern: '/assets/**', filters: 'none'],
[pattern: '/**/js/**', filters: 'none'],
[pattern: '/**/css/**', filters: 'none'],
[pattern: '/**/images/**', filters: 'none'],
[pattern: '/**/favicon.ico', filters: 'none'],
[pattern: '/api/**', filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'], // Stateless API
[pattern: '/**', filters: 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'] // Traditional, session based accesses.
]
The last 2 lines are the important bit; '/api/**' is secured by the Spring Security REST plugin which is a stateless connection (i.e. each request carries the authentication token). The '/**' rule covers everything else which requires a stateful session (the non-REST activity).
The stateless REST request will return 402 if the token has expired or is invalid in any way and the stateful non-rest will return 302 and send your browser round a loop.
Get those rules in the right order and you should be fine.