Grails, Spring Security & Siteminder - problems with resources or userDetails - grails

I am trying to secure my grails application with spring security basing on preAuth by Siteminder. That's basically all I need. The application is used just for checking some stuff so no need for database.
I am stuck on some filter problems that I'm somehow unable to embrace.
At first I used only RequestHeaderAuthenticationFilter and custom UserDetails and UserDetailsService.
My spring beans:
beans = {
userDetailsService(MyUserDetailsService)
userDetailsServiceWrapper(UserDetailsByNameServiceWrapper) {
userDetailsService = ref('userDetailsService')
}
preauthAuthProvider(PreAuthenticatedAuthenticationProvider) {
preAuthenticatedUserDetailsService = ref('userDetailsServiceWrapper')
}
requestHeaderAuthenticationFilter(RequestHeaderAuthenticationFilter){
principalRequestHeader='SM_USER'
authenticationManager = ref('authenticationManager')
}
}
I have my MyUserDetailsProvider:
class MyUserDetailsService implements GrailsUserDetailsService {
MyUserDetails loadUserByUsername(String username) throws UsernameNotFoundException{
//some super secret code here ;)
return new MyUserDetails(some needed params)
}
}
I also configured secured URLs like in every wise tutorial:
grails.plugins.springsecurity.interceptUrlMap = [
'/user/**':['ROLE_MINE'],
'/activation/**':['ROLE_SOMEOTHER, ROLE_MINE'],
'/js/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
'/css/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
'/images/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
'/*': ['IS_AUTHENTICATED_ANONYMOUSLY']
]
and some providers (left anonymous as advised in some tutorial):
grails.plugins.springsecurity.providerNames = ['preauthAuthProvider','anonymousAuthenticationProvider']
It was working great for data access but it was not allowing to load resources, images in particular. The error said that SM_USER header was not found in request.
So I thought that I can use some solution like 'filters: none' or 'security: none' so that spring would know what url request let without checking for SM_USER.
I tried adding stuff to filter and filterChain:
grails.plugins.springsecurity.filterNames = ['requestHeaderAuthenticationFilter']
grails.plugins.springsecurity.filterChain.chainMap = [
'/user/**': 'requestHeaderAuthenticationFilter',
'/activation/**': 'requestHeaderAuthenticationFilter',
'/*': 'requestHeaderAuthenticationFilter'
]
but it didn't help.
Then I tried using some other filter to be used on the resources without SM_USER header. From reference I understood that Anonymous filter might be enough.
So I made some changes:
grails.plugins.springsecurity.providerNames = ['preauthAuthProvider','anonymousAuthenticationProvider']
grails.plugins.springsecurity.filterNames = ['anonymousAuthenticationFilter','requestHeaderAuthenticationFilter']
grails.plugins.springsecurity.filterChain.filterNames = ['anonymousAuthenticationFilter','requestHeaderAuthenticationFilter'
]
grails.plugins.springsecurity.filterChain.chainMap = [
'/user/**': 'requestHeaderAuthenticationFilter',
'/versionone/**': 'requestHeaderAuthenticationFilter',
'/activation/**': 'requestHeaderAuthenticationFilter',
'/js/**': 'anonymousAuthenticationFilter',
'/css/**': 'anonymousAuthenticationFilter',
'/images/**': 'anonymousAuthenticationFilter',
'/*': 'requestHeaderAuthenticationFilter'
]
YAY that helped for images. But another problem started to occur.
Instead of myUserDetails object that should be returned when auth is correct I am obtaining some String object quite frequently. And my app is failing on inability to find one property in this String object (which is quite obvious as it's not there ;))
Does anyone know how to deal with that problem? Resigning from showing images is not an option ;)
Is there some way to exclude images/other resources from filterchain in spring security grails configuration...? Just like it was done in normal Java .xml way...?
I will appreciate all the help and suggestions how to solve this.
Thanks !!!
//EDIT: if by any chance anyone's using this as a reference to set up security for siteminder sso please note to add :
checkForPrincipalChanges = 'true'
invalidateSessionOnPrincipalChange = 'true'
properties to your requestHeaderAuthenticationFilter. Otherwise you will be dealing with not updated Authority in http session when calling springSecurityService.getPrincipal() hence users might be 'logged in as someone else'. :) Also consider changing scope of your beans to 'prototype'.

If anyone's interested - I found some workarounds for this issue:
1. Ask SiteMinder admin to add SM_USER header to all images or to some set of them limited to url location. This is disabled by default due to general performance. Then loose all additional filters and live happily ever after with preAuth one.
2. Use static content instead of including images in .war and redirect :]
HOW TO:
Put all needed images in var/www/yourfolder/images
Add some aliases to your httpd config :
Alias /yourapp/imgs var/www/yourfolder/images
ProxyPass /yourapp/imgs !
Restart your service
Be happy using images :D
I am aware that this is not the solution but only workaround. Yet it works.
I will be still happy to hear some better ideas :)
Cheers.

Related

jasig cas too many redirects issue

I'm trying to secure a spring-boot web application using spring security and spring-security-cas (SSO with Jasig CAS).
I'm facing a too many redirects error when trying to access a protected resources. The project is available here
Do you see any error in my configuration?
Thanks in advance
redirect loop error screenshot
Finally found out the error:
In SpringSecurity 4.x, CasAuthenticationFilter's defaultFilterProcessesUrl path is changed. So Change '/j_spring_cas_security_check' to '/login/cas' in Configuration.
So in my application.properties file, i had to change
app.service.security=http://localhost:7777/j_spring_cas_security_check
to
app.service.security=http://localhost:7777/login/cas
So the ServiceProperties Bean would become
#Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService("http://localhost:7777/login/cas");
serviceProperties.setSendRenew(false);
return serviceProperties;
}
Hope it'll help someone else!

Grails Spring Security LDAP plugin with multiple Active Directory servers

I have the Grails Spring Security plugin connecting to one Active Directory server with no problems. However, I need to connect to multiple servers. We have some users on one AD server and other users on a different server, so we need to try looking for users in both locations.
For example, in Java I have this working as below:
<authentication-manager>
<authentication-provider ref="provider1"/>
<authentication-provider ref="provider2"/>
...
</authentication-manager>
<ldap-server id="provider1"
url="ldap://LDAPSERVER1.mycompany.intranet"
manager-dn="OU=std_users,OU=users,DC=mycompany,DC=intranet"
manager-password="blah"/>
<ldap-server id="provider2"
url="ldap://DIFFERENT_LDAPSERVER.mycompany.intranet"
manager-dn="OU=std_users,OU=external_users,DC=mycompany,DC=intranet"
manager-password="blah"/>
In Grails I can configure one AD server but cannot work out how to configure more than one:
// LDAP config
grails.plugin.springsecurity.ldap.context.managerDn = 'CN=blah,OU=std_users,OU=users,DC=mycompany,DC=intranet'
grails.plugin.springsecurity.ldap.context.managerPassword = 'the_password'
grails.plugin.springsecurity.ldap.context.server = 'ldap://theserver.mycompany.intranet'
grails.plugin.springsecurity.ldap.authorities.ignorePartialResultException = true // typically needed for Active Directory
grails.plugin.springsecurity.ldap.search.base = 'OU=std_users,OU=users,DC=mycompany,DC=intranet'
grails.plugin.springsecurity.ldap.search.filter="sAMAccountName={0}" // for Active Directory you need this
grails.plugin.springsecurity.ldap.search.searchSubtree = true
grails.plugin.springsecurity.ldap.auth.hideUserNotFoundExceptions = false
I know that you can create a space-separated list of servers but this won't work for me as it will only try one of the servers once it has a connection, whereas I need it to try looking for users in both.
I think I probably need to get stuck into the resources.groovy file but don't know where to start with this - has anyone configured multiple AD locations?
The only other idea I have is to create a virtual directory which brings together all the users in one directory. Can anyone suggest a good way of doing this? I have been looking at http://myvd.sourceforge.net/usecases.html
Any help would be appreciated. Have been googling all day and I am no closer to a solution.
Andrew's answer pointed me in the right direction and I now have this working.
It was A LOT easier to make this work using ActiveDirectoryLdapAuthenticationProvider. This is done as below:
In resources.groovy:
// Domain 1
ldapAuthProvider1(ActiveDirectoryLdapAuthenticationProvider,
"mydomain.com",
"ldap://mydomain.com/"
)
// Domain 2
ldapAuthProvider2(ActiveDirectoryLdapAuthenticationProvider,
"mydomain2.com",
"ldap://mydomain2.com/"
)
In Config.groovy:
grails.plugin.springsecurity.providerNames = ['ldapAuthProvider1', 'ldapAuthProvider2']
This is all the code you need. You can pretty much remove all other grails.plugin.springsecurity.ldap.* settings in Config.groovy as they don't apply to this AD setup.
For documentation, see:
http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#ldap-active-directory
If you aren't using AD and want the 'pure LDAP' version:
In resources.groovy:
// Create another ldap authentication provider
ldapAuthProvider2(org.springframework.security.ldap.authentication.LdapAuthenticationProvider,
ref("ldapAuthenticator2"),
ref("ldapAuthoritiesPopulator") // Use default
) {
// Can set other auth provider settings here
}
ldapAuthenticator2(org.springframework.security.ldap.authentication.BindAuthenticator, ref("contextSource2")) {
userSearch = ref("ldapUserSearch2")
}
// Set up the manager to read LDAP
contextSource2(DefaultSpringSecurityContextSource, grailsApplication.config.grails.plugin.springsecurity.ldap.context.server2) {
userDn = grailsApplication.config.grails.plugin.springsecurity.ldap.context.managerDn2 // Manager DN
password = grailsApplication.config.grails.plugin.springsecurity.ldap.context.managerPassword2
}
// Configuration for searching for user
ldapUserSearch2(FilterBasedLdapUserSearch, grailsApplication.config.grails.plugin.springsecurity.ldap.search.base2, grailsApplication.config.grails.plugin.springsecurity.ldap.search.filter2, ref('contextSource2')) {
}
And then in Config.groovy:
// Config for second LDAP AuthenticationProvider - used in resources.groovy
grails.plugin.springsecurity.ldap.context.managerDn2 = 'CN=MANAGER_USER,OU=Users,DC=mycompany,DC=com'
grails.plugin.springsecurity.ldap.context.managerPassword2 = 'manager_password'
grails.plugin.springsecurity.ldap.context.server2 = "ldap://the-ldap-server.com"
grails.plugin.springsecurity.ldap.search.base2 = 'OU=Users,DC=mycompany,DC=com'
grails.plugin.springsecurity.ldap.search.filter2 = "sAMAccountName={0}" // for Active Directory you need this
// Add the AuthenticationProvider to the list
grails.plugin.springsecurity.providerNames = ['ldapAuthProvider', 'ldapAuthProvider2']
This link was very useful for finding out how to set this up:
https://github.com/grails-plugins/grails-spring-security-ldap/blob/master/SpringSecurityLdapGrailsPlugin.groovy
The basic idea would be to construct a second, custom AuthenticationProvider bean within your application's grails-app/conf/spring/resources.groovy file, perhaps modeling it after ldapAuthProvider in https://github.com/grails-plugins/grails-spring-security-ldap/blob/master/SpringSecurityLdapGrailsPlugin.groovy Then, you could add this custom LDAP authenticator bean to the grails.plugin.springsecurity.providerNames list in Config.groovy (or equivalent)

JSF 2 and the Basic HTTP authentication

We have an web app what uses Basic HTTP authentication.
web.xml
...
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>file</realm-name>
</login-config>
...
Indirect usage somewhere in the deep code space ...
User getLogedUser(HttpServletRequest request)
And I have to rewrite it in JSF 2, but I have no clue how can use the this authentication method in JSF 2. (i could not find the way how can i get 'HttpServletRequest request')
Google did not throw any useful hit on his first page
Thanks for the answers in advance.
The raw HttpServletRequest is in JSF available by ExternalContext#getRequest().
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
HttpServletRequest request = (HttpServletRequest) ec.getRequest();
// ...
However, I think it's better to change the getLoggedUser() method to take the remote user instead.
User getLoggedUser(String remoteUser)
so that you can just feed either ExternalContext#getRemoteUser() or HttpServletRequest#getRemoteUser() to it. This also decouples the method from any Servlet API or JSF API dependency.
I guess you are looking for ExternalContext.getRemoteUser()
which returns the user name.
Usage:
FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();

Grails Spring Security Core Plugin

I am (finally) upgrading my Acegi plugin to Spring Security Core. At the same time, I am upgrading from Grails 1.3.7 to 2.0. My site was fully functional before, but now when I try to get to my default page (which is IS_AUTHENTICATED_ANONYMOUSLY) I am redirected to the auth action of my LoginController. This method was never invoked with Acegi, so I don't know what the problem is. Have I set up my configuration wrong or is there something else I need to be thinking about?
grails.plugins.springsecurity.securityConfigType = SecurityConfigType.InterceptUrlMap
grails.plugins.springsecurity.interceptUrlMap = [
'/blog/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/static/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/consensus/**':['IS_AUTHENTICATED_FULLY'],
'/login/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/signup/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/home/**':['IS_AUTHENTICATED_FULLY'],
'/test/**':['ROLE_ADMIN'],
'/admin/**':['ROLE_ADMIN'],
'/adminmanage/**':['ROLE_ADMIN'],
'/quartz/**':['ROLE_ADMIN'],
'/**/*.css':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/js/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/images/**':['IS_AUTHENTICATED_ANONYMOUSLY'],
'/monitoring**':['ROLE_ADMIN'],
'/**':['IS_AUTHENTICATED_FULLY']
]
My UrlMappings.groovy is:
class UrlMappings {
static mappings = {
"/"(controller:"x", action:"y")
"/z/?"(controller:"x", action:"y")
"/$controller/$action?/$id?"
{
constraints {
// apply constraints here
}
}
"500"(view: '/error')
}
}
I have been reading through the documentation but am having some problems, so I am not sure if there is more relevant code one would need to see. If there is, please let me know and I will add it. Thanks.
Other options in my Config.groovy were incorrect and this caused the problem. Once I corrected them everything worked fine.
Despite it being called out in the documentation, I had security fields that were not prepended with grails.plugins.springsecurity This caused the engine not to recognize them, which for some reason resulted in the call to auth.
After remove openid plugin all requests redirects me to the login page! I don't know what to do... I've already remove everything related.

symfony 1.4 how to turn off csrf protection for one registration form?

I'm using both sfDoctrineGuard and sfForkedDoctrineApply. I've written a module that permits a logged-in user to create a child-user which inherits a few of the parent's profile settings. It works great, the way it is written, however I have to turn off csrf protection for the whole app (in settings) in order to get it working because when it is turned on, it (rightfully, I might add) detects a csrf attack. So, I need a way to turn it off, or at least catch and remove the validation.
I've tried many techniques, none of which have worked. Including:
$this->disableLocalCSRFProtection();
in the form. Problem is, it's a custom form and the parent config is being called which is injecting the csrf protection.
I've read a few solutions that I think are pointing in the right direction: Symfony 1.4: Custom error message for CSRF in forms but they don't address this specific problem.
Suggestions and solutions are welcome. Thanks in advance.
The base sfForm constructor configures whether enabled and what will be the CSRFSecret.
class sfForm implements ArrayAccess, Iterator, Countable
{
public function __construct($defaults = array(), $options = array(), $CSRFSecret = null)
{
$this->setDefaults($defaults);
$this->options = $options;
$this->localCSRFSecret = $CSRFSecret;
$this->validatorSchema = new sfValidatorSchema();
$this->widgetSchema = new sfWidgetFormSchema();
$this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
$this->setup();
$this->configure();
$this->addCSRFProtection($this->localCSRFSecret);
$this->resetFormFields();
}
}
In such cases, where disabling local CSRF protection via disableLocalCSRFProtection() doesn't work, you may try to create the form instance with a "false" CSRFSecret".
Example:
$myForm = new myForm(array(), array(), false);
Edit: (The above suggestion didn't work for the poster)
Could you please try, just commenting the "csrf_secret" configuration in your application's settings.yml. After commenting this line, don't forget to clear symfony's cache. To verify that CSRF protection is disabled globally, you may check the value of the "sf_csrf_secret" configuration as follows;
var_dump(sfConfig::get('sf_csrf_secret'))
This should give you a boolean false, which implies in deed all CSRF protection is disabled.
$this->disableLocalCSRFProtection(); didn't work for me either.
I succeeded by setting the crsf validator required option to false right after create the form.
<?php
$form = new UploadImageForm();
$form->getValidator($form->getCSRFFieldName())->setOption('required', false);
if ($request->isMethod(sfWebRequest::POST)) {
...
?>

Resources