I have a Grails application with spring-security-ldap plugin installed and configured with Active Directory specific options.
Grails version: 2.1.1.
spring-security-core plugin version: 2.0-RC2
spring-security-ldap plugin version: 2.0-RC2
Everything works fine: users log in to the application validating against the Active Directory and their groups are retrieved in order to control the access to the different pages.
My problem: "remember me" option doesn't work. I have configured the application in order to use "remember me" option and I have run the s2-create-persistent-token command. I have also activated the specific traces.
Everything works fine: the user successfully logs in to the application with the "remember me" option checked, the token is created and the cookie is sent to the client. The user closes the browser and then reopens it. At this point, the application successfully validates that the user in the cookie matches with the user in the persistent token.
Then I can see this in the log
userdetails.LdapUserDetailsManager - Loading user 'sAMAccountName' with DN 'cn=sAMAccountName,dc=company,dc=country'
rememberme.PersistentTokenBasedRememberMeServices - Remember-me login was valid but corresponding user not found.
Message: User sAMAccountName not found
Line | Method
->> 49 | doFilter in grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 82 | doFilter in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker
| 908 | run in ''
^ 619 | run . . in java.lang.Thread
Caused by NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031001CD, problem 2001 (NO_OBJECT), data 0, best match of:
'DC=company,DC=country'
The first log line shows a not valid DN for the user. The DN for the user is something like this
cn=name,ou=a group,ou=a super group,dc=company,dc=country
Could be that the problem? How can I solve it?
My configuration
// Spring Security
grails.plugin.springsecurity.logout.postOnly = false
// Spring Security LDAP
grails.plugin.springsecurity.ldap.context.managerDn = 'CN="a user",OU="a group",DC="company",DC="country"'
grails.plugin.springsecurity.ldap.context.managerPassword = '"password"'
grails.plugin.springsecurity.ldap.context.server = 'ldap://"server":389'
grails.plugin.springsecurity.ldap.authorities.ignorePartialResultException = true
grails.plugin.springsecurity.ldap.search.base = 'dc="company",dc="country"'
grails.plugin.springsecurity.ldap.search.filter="sAMAccountName={0}"
grails.plugin.springsecurity.ldap.search.searchSubtree = true
grails.plugin.springsecurity.ldap.auth.hideUserNotFoundExceptions = false
grails.plugin.springsecurity.ldap.search.attributesToReturn = ['dn', 'cn', 'ou', 'givenName', 'sn', 'department']
grails.plugin.springsecurity.ldap.authenticator.attributesToReturn = ['dn', 'cn', 'ou', 'givenName', 'sn', 'department']
grails.plugin.springsecurity.providerNames = ['ldapAuthProvider','anonymousAuthenticationProvider', 'rememberMeAuthenticationProvider']
// role-specific LDAP config
grails.plugin.springsecurity.ldap.authorities.retrieveGroupRoles = true
grails.plugin.springsecurity.ldap.authorities.groupSearchBase = 'dc="company",dc="country"'
grails.plugin.springsecurity.ldap.authorities.groupSearchFilter = '(member:1.2.840.113556.1.4.1941:={0})' // Active Directory specific
grails.plugin.springsecurity.successHandler.defaultTargetUrl = '/home'
grails.plugin.springsecurity.rememberMe.persistent = true
grails.plugin.springsecurity.rememberMe.persistentToken.domainClassName = 'censo.auth.PersistentLogin'
grails.plugin.springsecurity.ldap.useRememberMe = true
grails.plugin.springsecurity.ldap.rememberMe.detailsManager.groupMemberAttributeName = 'member'
grails.plugin.springsecurity.ldap.rememberMe.detailsManager.groupRoleAttribute = 'CN'
grails.plugin.springsecurity.ldap.rememberMe.detailsManager.groupSearchBase = 'OU="another group",dc="company",dc="country"'
grails.plugin.springsecurity.ldap.rememberMe.detailsManager.passwordAttributeName = 'userPassword'
grails.plugin.springsecurity.ldap.rememberMe.usernameMapper.userDnBase = 'dc="company",dc="country"'
grails.plugin.springsecurity.ldap.rememberMe.usernameMapper.usernameAttribute = 'cn'
grails.plugin.springsecurity.ldap.rememberMe.detailsManager.attributesToRetrieve = null
Thank you in advance
Related
I'm using 5.3 version and I've configured CAS for delegating authentication to an external Oauth server. My cas.properties looks like:
cas.authn.pac4j.oauth2[0].clientName=oauth1
cas.authn.pac4j.oauth2[0].id=
cas.authn.pac4j.oauth2[0].secret=
cas.authn.pac4j.oauth2[0].authUrl=https://xxxxxxxxxxx/sso/oauth/controller/Server/action/authorize/
cas.authn.pac4j.oauth2[0].tokenUrl=https://xxxxxxxx/sso/oauth/controller/Server/action/token/
cas.authn.pac4j.oauth2[0].profileUrl=https://xxxxxxxx/sso/oauth/controller/Server/action/profile/?fields=username
cas.authn.pac4j.oauth2[0].principalAttributeId=username
In terms of service (JSON) this is the configuration:
{
#class: org.apereo.cas.services.RegexRegisteredService
serviceId: ID
name: name
theme: default
id: 1
description: name
logoutType: FRONT_CHANNEL
attributeReleasePolicy:
{
"#class" : "org.apereo.cas.services.ReturnAllAttributeReleasePolicy"
}
logoutUrl: https://yyyyyy/logout
accessStrategy:
{
#class: org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy
order: 0
enabled: true
ssoEnabled: true
delegatedAuthenticationPolicy:
{
"#class": "org.apereo.cas.services.DefaultRegisteredServiceDelegatedAuthenticationPolicy"
"allowedProviders" : [ "java.util.ArrayList", [ "oauth1" ] ]
}
requireAllAttributes: false
caseInsensitive: false
}
}
CAS is able to get properly the information from Oauth protocol but when it tries to get the Principal, the answer is always:`
2019-10-31 14:37:41,070 DEBUG [org.apereo.cas.authentication.DefaultAuthenticationBuilder] - <Recording authentication handler result success under key [ClientAuthenticationHandler]>
2019-10-31 14:37:41,070 DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Authentication handler [ClientAuthenticationHandler] successfully authenticated [ClientCredential(typedIdUsed=false, userProfile=#OAuth20Profile# | id: null | attributes: {access_token=8b2eaaa3c8d3d51233df5da4047889c8530a7df4, username=apotheke_alphega} | roles: [] | permissions: [] | isRemembered: false | clientName: oauth1 | linkedId: null |, credentials=#OAuth20Credentials# | code: 5f0d498cfc347b66de544d98ce309d5f1f200716 | accessToken: com.github.scribejava.core.model.OAuth2AccessToken#3b3a98c |, clientName=oauth1)]>
2019-10-31 14:37:41,074 DEBUG [org.apereo.cas.config.CasPersonDirectoryConfiguration] - <Configured single-row JDBC attribute repository for [jdbc:mysql://b2bde-uat-db02.mysql.database.azure.com/lr_b2b_core?useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true]>
2019-10-31 14:37:41,086 WARN [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <[ClientAuthenticationHandler] is configured to use [ChainingPrincipalResolver(principalFactory=org.apereo.cas.authentication.principal.DefaultPrincipalFactory#1, chain=[EchoingPrincipalResolver(), PersonDirectoryPrincipalResolver(attributeRepository=org.apereo.services.persondir.support.CachingPersonAttributeDaoImpl#63f2c17b, principalFactory=org.apereo.cas.authentication.principal.DefaultPrincipalFactory#1, returnNullIfNoAttributes=true, principalNameTransformer=org.apereo.cas.authentication.principal.resolvers.PersonDirectoryPrincipalResolver$$Lambda$130/1783977388#2488625b, principalAttributeNames=username, useCurrentPrincipalId=true)])] but it does not support [ClientCredential(typedIdUsed=false, userProfile=#OAuth20Profile# | id: null | attributes: {access_token=8b2eaaa3c8d3d51233df5da40478df4, username=user} | roles: [] | permissions: [] | isRemembered: false | clientName: oauth1 | linkedId: null |, credentials=#OAuth20Credentials# | code: 5f0d498cfc347b66de544d98ce30916 | accessToken: com.github.scribejava.core.model.OAuth2AccessToken#3b3a98c |, clientName=oauth1)], which suggests a configuration problem.>
2019-10-31 14:37:41,087 WARN [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Principal resolution handled by [$Proxy401] produced a null principal. This is likely due to misconfiguration or missing attributes; CAS will attempt to use the principal produced by the authentication handler, if any.>
2019-10-31 14:37:41,087 WARN [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Principal resolution for authentication by [ClientAuthenticationHandler] produced a null principal.>
2019-10-31 14:37:41,087 DEBUG [org.apereo.cas.authentication.PolicyBasedAuthenticationManager] - <Final principal resolved for this authentication event is [null]>
Could you help me? I'm very block and I can't find any real example
Kind Regards
I'm working on grails 2.4.5.
I connect my project to oracle 11g.
In datasource, I add:
dataSource {
pooled = true
dialect = org.hibernate.dialect.Oracle10gDialect
driverClassName = 'oracle.jdbc.OracleDriver'
username = 'grails' // YOUR USERNAME AND PASS
password = 'grails'
url = 'jdbc:oracle:thin:localhost:1521:orcl'
dbCreate = 'update'
}
Then it connects and when I create new domain, new table in db creates.
However when I add new:
new Book(name:'The Strain').save(flush:true)
Then errors appear:
2015-07-29 17:10:30,036 [Thread-10] ERROR plugins.AbstractGrailsPluginManager - Plugin [controllers:2.4.5] could not reload changes to file [C:\Users\Thuc Tran\IdeaProjects\EmailTutorial\grails-app\controllers\emailtutorial\PlaceController.groovy]: Cannot invoke method getPropertyValue() on null object
Message: Cannot invoke method getPropertyValue() on null object
Line | Method
->> 120 | configureScaffoldingController in ScaffoldingGrailsPlugin
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
^ 105 | doCall in ScaffoldingGrailsPlugin$_closure3
Any solutions will be appreciated. Thanks.
I solved this problem. I post the solution for those who need it.
On oracle, create sequence, eg: BOOK_SEQ on my case. Make sure that on oracle, when you add new record, id will be auto increment.
Then on the domain class, static mapping quote, add:
static mapping = {
id generator:'sequence', params:[sequence:'BOOKS_SEQ']
}
So that's all.
If answer not clear, I feel free to answer.
Thanks.
using the spring security core plugin I am trying to catch event so I am using
grails.plugin.springsecurity.useSecurityEventListener = true
grails.plugin.springsecurity.onInteractiveAuthenticationSuccessEvent = { e, appCtx ->
def request = org.codehaus.groovy.grails.plugins.springsecurity.SecurityRequestHolder.getRequest()
def session = request.getSession(false)
session.myvar=2
}
but it give me :
2014-06-08 21:49:05,333 [http-bio-8080-exec-6] ERROR [/ammc].[default] - Servlet.service() for servlet [default] in context with path [/ammc] threw exception
Message: No signature of method: groovy.util.ConfigObject.getRequest() is applicable for argument types: () values: []
Line | Method
->> 158 | doCall in Config$_run_closure5
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 95 | call in grails.plugin.springsecurity.SecurityEventListener
| 72 | onApplicationEvent in ''
| 49 | doFilter in grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
| 82 | doFilter . . . . . in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
notice that the line 158 in the config file is exactly the line
def request = org.codehaus.groovy.grails.plugins.springsecurity.SecurityRequestHolder.getRequest()
which is crazy because I am not invoking groovy.util.ConfigObject.getRequest() in this line
I already tried to clean and compile but nothing change.
and at the same time if I want to catch the failure login event, what event I must catch?
update
I am using grails 2.3.8 and spring-security-core:2.0-RC2
To answer the question
This may be late but...
I believe you mean
def request = grails.plugin.springsecurity.web.SecurityRequestHolder.getRequest()
(note the different package name)
This may not be of much help to #Bilel but it may be to anyone else who happens upon the question.
One a side note:
which is crazy because I am not invoking groovy.util.ConfigObject.getRequest() in this line
When you see weird things like groovy.util.ConfigObject I have come to notice that it usually means a variable in Config does not exist.
Also, on another note:
I don't know if doing it in Config.groovy is an absolute requirement but I believe this gets cleaner if you register a listener.
Here's what I would do:
import org.springframework.context.ApplicationListener
import org.springframework.security.authentication.event. InteractiveAuthenticationSuccessEvent
class MyLoginListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {
void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
def request = grails.plugin.springsecurity.web.SecurityRequestHolder.getRequest()
def session = request.getSession(false)
session.myvar=2
}
}
and then register it in resources.groovy
beans = {
myLoginListener(MyLoginListener)
}
You need the following line in Config.groovy, but you may already have it there anyway.
grails.plugin.springsecurity.useSecurityEventListener = true
A confused Grails newbie here. I am currently going through the tutorials in
a book (Smith, Ledbrook, "Grails in Action", Manning Publications, 1st Ed)
and am stumped in the first chapter! When browsing to localhost, I get the
error messages further below. The tutorial leads me through creating a
Random Quote of the Day application. As you might suspect, browsing to the
webpage gives a random quote (which were saved in the "Quote" domain class)
with each refresh.
I have made the controller, view, layout, domain class, all of which are
pretty simple. I would imagine that I'd get these errors if there were no
test data, but using the grails console shows me that there are. Despite
this, refreshes of the browser echo the errors in an open terminal.
The code for the Quote domain class and the controller are below as well. I
wanted to change the config file for the development environment to make it
persistent, so that entry is also down there. Let me know if you need to see
anything else...
Any ideas? (Using Grails version 2.4.0 installed on Ubuntu 14.04. Book uses
code for Grails 1.1)
Error:
URI: /qotd/quote/random
Class:java.lang.IllegalStateException
Message: Method on class [qotd.Quote] was used outside of a Grails
application. If running in the context of a test using the mocking API or
bootstrap Grails correctly.
Around line 8 of grails-app/controllers/qotd/QuoteController.groovy
6:
7: def random = {
8: def allQuotes = Quote.list()
9: /*def randomQuote
10: if (allQuotes.size() > 0 )
11: {
Trace
Line | Method
->> 9 | doCall in QuoteController.groovy
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 198 | doFilter in PageFragmentCachingFilter.java
| 63 | doFilter in AbstractFilter.java
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 744 | run in java.lang.Thread
Controller
package qotd
class QuoteController {
def index = { }
def random = {
def allQuotes = Quote.list()
/*
def randomQuote
if (allQuotes.size() > 0 )
{
def randomIdx = new Random().nextInt(allQuotes.size())
randomQuote = allQuotes[randomIdx]
} else {
randomQuote = new Quote(author: "Anonymous",
content: "Real Programmers Don't eat Quiche")
}
[quote : randomQuote ]
*/
}
}
Quote domain class
package qotd
class Quote {
String content
String author
Date created = new Date()
static constraints = {
}
}
Development Environment from DataSource.groovy
development {
dataSource {
dbCreate = "update" // one of 'create', 'create-drop', 'update',
'validate', ''
url =
"jdbc:h2:file:~/h2db/quotedevdb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE"
}
}
Yep, as grantmcconnaughey comments, you don't want to declare your controller actions as closures with an '=' sign. It is now recommended to use methods. So you can do:
def random() {
def allQuotes = Quote.list()
}
or:
public random() {
def allQuotes = Quote.list()
}
See the online docs.
i'm a bit new on the groovy grails technology and i'm having a problem with this one
i looked at this could not initialize proxy - no Session but the application don't get stale too long
I am trying to access the session object on my SecurityFilter placed on the config subfolder. I just wanted to do a check for every request on the controllers to verify if a user has the rights to do such actions.
class SecurityFilters {
def filters = {
userFilterList(controller:"user", action:"list") {
before = {
if (!session.user.accountType.equals("Admin")) {
redirect(uri: "/")
}
}
}
userFilterShow(controller:"user", action:"show") {
before = {
if (!session.user.accountType.equals("Admin")) {
redirect(uri: "/")
}
}
}
userFilterEdit(controller:"user", action:"edit") {
before = {
if (!session.user.accountType.equals("Admin")) {
redirect(uri: "/")
}
}
}
}
}
but I get this error
Message: could not initialize proxy - no Session
Line | Method
->> 6 | doCall in SecurityFilters$_closure1_closure2_closure5
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 186 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 1110 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 603 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 636 | run in java.lang.Thread
before I get to this point I placed the user object on the session object right after doing the login instructions but I am not sure what happened that the session object became not available
some of the properties of the user object were not retrieved, so in the login when I put the user object in the on the session, I also had to manually transfer the property that I needed so I could retrieve again for later use
session.user = user //not enough
session.user.accountType = user.accountType
now I was able to retrieve the user object from the session object and get the property that I wanted to get