grails application access after authentication with ldap role based authorization - grails

Our grails application uses ldap authentication, without any problems, now I need to prevent access, to the entire application, if a user has no specific ldap role.
I can see the role and use it in my Config.groovy annotations or secure the actions in the controllers, but instead I need a scenario/way to just show a "Denied ..." message and logout. (POST Forbidden 403).
def filters = {
loginFilter(controller:'login', action:'ajaxSuccessSproutcore') {
before = {
switch(Environment.current.name) {
case { it == 'development' || it == 'hrm'}:
if (springSecurityService.isLoggedIn() && grails.plugin.springsecurity.SpringSecurityUtils.ifAnyGranted("ROLE_ADMIN, ROLE_SEA_HRM_LOGIN")){
} else {
if (springSecurityService.isLoggedIn()) {
render ([msg:''] as JSON)
session.invalidate()
return false
}
}
break
default:
if (springSecurityService.isLoggedIn() && grails.plugin.springsecurity.SpringSecurityUtils.ifAnyGranted("ROLE_ADMIN , ROLE_USER")){
} else {
if (springSecurityService.isLoggedIn()) {
render ([msg:''] as JSON)
session.invalidate()
return false
}
}
break
}
}
after = { Map model ->
}
afterView = { Exception e ->
}
}
}

In grails 3 you can set up an Interceptor to check every request and take the appropriate action. In your case you'd want to add a check in the before block.
Edit: As Jeff Brown notes in the comments, grails 2 used Filters rather than interceptors.
Edit: Something like this in your logout logic:
...
else {
if (springSecurityService.isLoggedIn()) {
session.invalidate()
redirect action:'youShallNotPass'
return false
}
}

Related

Mapping client role from external source in Keycloak

I successfully implemented User storage SPI in keycloak. Now I am able to do authentication from external REST source. Now I want to get client roles from external source. I am receiving a user entity as follows:
{
"id": "78c8ee03-0bf8-422a-91ec-6241624c0683",
"username": "kaushikam",
.....
"roles": [
{
"id": 1,
"name": "heroes"
"client": "heroes-client"
}
]
}
In keycloak server, I have manually created a client with the name heroes-client and in that client I have added the client role heroes. Now I want to map the client role received from external source to the client role in the client named heroes-client.
I used the getClientRoleMappings in UserModel as follows:
override fun getClientRoleMappings(app: ClientModel?): MutableSet<RoleModel> {
logger.info { "Calling getClientRoleMappings" }
val userRoles = this.user?.roles?.filter { it.client == app?.name } ?: emptyList()
val clientRoles = mutableSetOf<RoleModel>()
userRoles.forEach {
if (app != null) {
clientRoles.add(app.getRole(it.name))
}
}
return clientRoles
}
But the above code is not being called. While getRoleMappings is called. Is there anyway to solve this issue.
You can get the whole source code of my work here
I solved the issue. I think there is currently no need of getClientRoleMappings method. My need can be achieved using the getRoleMappings method. I thought that method was only used for realm roles, but that's not the case. Below is the updated code for getRoleMappings:
override fun getRoleMappings(): MutableSet<RoleModel> {
val roles = addRealmRoles()
return addClientRoles(roles)
}
private fun addRealmRoles(): MutableSet<RoleModel> {
val roles = mutableSetOf<RoleModel>()
user?.roles?.forEach { roleDTO ->
if (realm != null) {
val realmRole = realm.getRole(roleDTO.name) ?: null
if (realmRole != null) {
roles.add(realmRole)
}
}
}
return roles
}
private fun addClientRoles(roles: MutableSet<RoleModel>): MutableSet<RoleModel> {
user?.roles?.forEach { roleDTO ->
realm?.clientsStream?.forEach { client ->
client.rolesStream.forEach { clientRole ->
if (client.clientId == roleDTO.client && clientRole.name == roleDTO.name) {
roles.add(clientRole)
}
}
}
}
return roles
}
I have also updated the repository. You can see whole source code there

HTTPS routing suddenly stopped working in Grails

In my Grails 2.5.1 application , i was using a filter to use HTTPS with some controllers , everything was working fine but suddenly this filter is not working any more .
Filter :
def filters = {
all(controller:'checkout', action:'onlinePayment') {
before = {
if (!request.isSecure() /*&& !Environment.isDevelopmentMode()*/) {
def url = "https://" + request.serverName+':8443' + request.forwardURI
println "in filter"
redirect(url: url, permanent: true)
return false
}
}
after = { Map model ->
}
afterView = { Exception e ->
}
}
}
Here is the checkout page :
Also i found that no requests came to the filter as in filter was not printed out, is there something i need to check to fix this issue rather than this filter

login date in spring security plugin for Grails

i'm using spring security plugin , i want to save the user's login date in the DB so i wrote the below in the config file :
grails.plugin.springsecurity.useSecurityEventListener = true
grails.plugin.springsecurity.onAuthenticationSuccessEvent= { e, appCtx ->
com.app.utils.UserActivity.withTransaction {
def user = com.app.utils.UserActivity.findByUser(com.app.security.Users.get(appCtx.springSecurityService.principal.id))
if (!user)
{
new com.app.utils.UserActivity(user:user,userLoggedIn:new Date(),userLoggedOut: null).save(failOnError:true)
}
else
{
user.userLoggedIn= new Date()
user.userLoggedOut=null
user.save(failOnError:true)
}
}
}
the issue is that appCtx.springSecurityService.principal.id is always returning null , and are there any events for the logout action.
The correct way to get the pricipal is from the authentication event like this:
e.getAuthentication().getPrincipal()

Grails channel security causing a redirect loop

I am new to Grails and I am working on an exisiting application. I am trying to force the anyone using our website to allways be on https. I added the Spring Security Core plugin
//BuildConfig.groovy
compile "org.grails.plugins:spring-security-core:2.0.0"
and I just added
///Config.groovy
grails.plugin.springsecurity.secureChannel.definition = [
'/**': 'REQUIRES_SECURE_CHANNEL'
When I try to go on localhost:8080/myapp, it redirects me to https://localhost:8443/myapp, but I get a "This webpage has a redirect loop ERR_TOO_MANY_REDIRECTS" message.
I added print statements in my SecurityFilters.groovy, and I can see the infinite loop going
baseFilter(controller: "*", action: "*")
{
before = {
println "baseFilter"
// If auth controller then ok to continue
if (controllerName.equals("auth"))
{
return true;
}
// If no subject (user) and not auth controller then user must authenticate
if (!session.subject && !(controllerName.equals("auth")))
{
params.targetUri = request.forwardURI - request.contextPath
if (params.action=="profile") {
params.targetUri=params.targetUri + "?page=" + params?.page
}
else if (params.action=="results") {
params.targetUri="/home"
}
println "baseFilter: Redirecting: PARAMS = $params"
redirect(controller:'auth', action:'login', params: params)
return false;
}
}
}
It's just:
baseFilter
baseFilter: Redirecting: PARAMS = [action:auth, format:null, controller:login, targetUri:/login/auth]
Over and over.
I've tried many other things I found on Stackoverflow and other websites, but they either do not work, or are too complicated.
Thank you.
Ok, so this isn't the answer to the question, but I managed to achieve what I was trying to do, which was to force SLL, and redirect any attempts to use http. I did this by using the shiro plugin, which was already being used by my application. In the Buildconfig.groovy, just add compile ":shiro:1.2.1" to you plugins. In the config.groovy I added the following properties:
security {
shiro {
filter {
loginUrl = "/login"
successUrl = "/"
unauthorizedUrl = "/unauthorized"
filterChainDefinitions = """
/** = ssl[443]
"""
}
}
}
You can modify your filterChainDefinitions to only force ssl on certain urls. I just used /** because I always want SSL.

Logic block in Grails URLMappings

My site has urls like 'http://someRandomUsername.mysite.com'.
Sometimes users will try urls like
'http://www.someRandomeUsername.mysite.com'. I'd like to have some
logic in my url mappings to deal with this.
With the mappings below when I hit the page , with or without the
unneeded www, I get:
2012-03-01 14:52:16,014 [http-8080-5] ERROR [localhost].[/ambit] -
Unhandled exception occurred whilst decorating page
java.lang.IllegalArgumentException: URL mapping must either provide a
controller or view name to map to!
Any idea how to accomplish this? The mapping is below.
Thanks!
Jason
static mappings = {
name publicMap: "/$action?/$id?" {
def ret = UrlMappings.check(request)
controller = ret.controller
userName = ret.userName
}
}
static check =
{ request ->
def tokens = request?.serverName?.split(/\./) as List ?: []
def ret = [controller:'info']
if(tokens.size() > 3 && token[0] == 'www')
{
ret.userName = tokens[1]
ret.controller = 'redirect'
ret.action = 'removeWWW'
}
else if(tokens.size() == 3)
{
ret.userName = tokens[0]
ret.controller = 'info'
}
return ret
}
Honestly, like DmitryB said, the best way to do this is via the web server, whether it's IIS, Apache, or Tomcat.
Having said that, I feel the best way to accomplish this in Grails would be using filters.
You could create something like this in your ~/conf directory:
public class StripFilters {
def filters = {
stripWWWFilter(controller: '*', action: '*') {
before = {
def tokens = request.serverName.tokenize(/\./) ?: []
if(tokens.size() > 3 && tokens[0] == 'www') {
def url = request.request.requestURL.toString().replace('www.', '')
redirect([url:url, params: [userName: tokens[1]], permanent: true])
return false
}
}
}
}
}
This should do the trick.

Resources