LDAP authentication without managerDN and manager password - spring-security

I am writing an application in Java Spring framework to perform Active Directory LDAP authentication.
I am succeeding in connecting to my organization LDAP.
Here is the configuration settings:Spring-security.xml
<!-- This is where we configure Spring-Security -->
<security:http auto-config="true" use-expressions="true"
access-denied-page="/oops">
<security:intercept-url pattern="/auth/*"
access="isAuthenticated()" />
<security:logout invalidate-session="true"
logout-success-url="/" logout-url="/logout" />
</security:http>
<security:authentication-manager>
<security:ldap-authentication-provider
user-search-filter="(&(sAMAccountname={0})(objectCategory=user))"
user-search-base="DC=am, DC=example, DC=com" group-search-filter="(&(sAMAccountname={0})(objectCategory=group))"
group-search-base="DC=am, DC=example, DC=com">
</security:ldap-authentication-provider>
</security:authentication-manager>
<security:ldap-server url="ldaps://myserver.am.example.com:4567"
manager-dn="CN=Johnson \, Mitchell, OU=San Francisco,DC=am,DC=example,DC=com"
manager-password="sdvsdvsvs" />
My question here is that,is there any way to authenticate LDAP without supplying manager-dn and manager-password in security:ldap-server tag.
Please provide a solution to this.Thanks in advance.

Yes it is possible: you can let the user who is actualy logging in connecting to the LDAP himself to test his credential and fetch its userdata.
AuthenticationManager configuration:
#Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider = new ActiveDirectoryLdapAuthenticationProvider(domain, url, rootDn);
activeDirectoryLdapAuthenticationProvider.setSearchFilter(searchFilter);
auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider);
}
Spring security does two things:
Let the user log in with his username and password
Find the user to fetch user info, groups, etc. For this step, you must specify a searchFilter that can find a user based on it's username, like "userPrincipalName={0}" where {0} is the provided username.

Define an administrative user who has the necessary permissions, and use that. You certainly shouldn't use the managerDN for anything in your application.

Related

#PreAuthorize and intercept-url priority

I have
<security:http use-expressions="true">
<security:intercept-url pattern="/**/*" access="hasRole('ROLE_USER')"/>
in the Spring Security context configuration file and
#PreAuthorize("permitAll")
#RequestMapping("/public")
public String aMethod() {
// ...
}
in a controller.
What I want is that all the URLs to require authentication except public. Is this possible?
<intercept-url> in XML takes precedence over annotations. <intercept-url> works at URL level and annotations at method level.
If you are going to use spring security and spring <form-login /> then the approach below would serve you better.
<intercept-url pattern="/public/**"
access="permitAll" />
<intercept-url pattern="/restricted/**"
access="hasAnyRole('ROLE_USER', 'ROLE_ADMIN', 'ROLE_SOME')
#PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_SOME')")
#RequestMapping("/restricted/aMethod")
public String aMethod() {
// ...
}
Anything under restricted can be accessed by three different roles. But specific path restricted/aMethod can be accessed by #PreAuthorize("ROLE_ADMIN") and #PreAuthorize("ROLE_SOME") but NOT by #PreAuthorize("ROLE_USER"). By default all three roles can access but when you mark some path with #PreAuthorize("ROLE_ADMIN") then user with ROLE_ADMIN can access that path.
If you think about it, #PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_SOME')") act as narrowed or filtered access from a large set of ROLES to single(or set of roles) ROLE.
As you would notice, none of /restricted paths are accessible by permitAll. Its preferred to have /static/*.css and others under permitAll.
HTH

Spring security access denied message when accessing login page after login successfully.It should redirect to default page

Configured spring security successfully
Authentication properly working
Problem is that after login successfully if user access login page, access denied message appears.It must redirect to default page as user already login.
When i access login.html after login successfully , access denied message appears.
Here's my code
<http auto-config="true">
<intercept-url pattern="/login.html" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/services/**" filters="none"/>
<intercept-url pattern="/**" access="ROLE_ADMIN" />
<form-login login-page="/login.html" default-target-url="/stations.html" always-use-default-target="true" />
<logout logout-url="/logout" logout-success-url="/login.html"/>
<intercept-url pattern="/css/**" filters="none"/>
<intercept-url pattern="/js/**" filters="none"/>
<intercept-url pattern="/images/**" filters="none"/>
<intercept-url pattern="/common/**" filters="none"/>
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
SELECT USERNAME,PASSWORD,USER_STATUS as ENABLED
from USERS where USERNAME=?"
authorities-by-username-query="
SELECT USERNAME, USER_ROLE from USERS
where USERNAME =? "
/>
</authentication-provider>
</authentication-manager>
When the user successfully loggs in this means he/she has some role (admin for example). This is different than ROLE_ANONYMOUS. You can try:
<intercept-url pattern="/login.html" access="ROLE_ANONYMOUS, ROLE_ADMIN,..any other role" />
or even better
<intercept-url pattern="/login.html" filters="none" />
One suggestion: Spring Security evaluate the intercept-url elements in the order you write them in the xml, so you should put the most "greedy" intercept-url at the end. E.g. <intercept-url pattern="/**" access="ROLE_ADMIN" /> will catch everything. The intercept-url for css, js... will never be reached. You should place them first.
I face the same problem,
I have already search many resources and did not found what I looking for.
At last, I'm doing this:
public class SSOInit extends HandlerInterceptorAdapter {
private static final Logger logger = Logger.getLogger(SSOInit.class.getName());
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.info("### SSO : doInit, read page");
logger.info("### SSO : request url = " + request.getRequestURL());
logger.info("### SSO : request method = " + request.getMethod());
CredentialVO credential = SSOService.getUserCredential();
if (credential != null) {
logger.info("### SSO : credential found, do check point");
String status = SSOService.checkSSOSessionKey();
if (status == null || status.equals("T")) {
logger.info("### SSO : Check point didn't passed, redirect");
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
new SecurityContextLogoutHandler().logout(request, response, auth);
}
SecurityContextHolder.getContext().setAuthentication(null);
} else {
logger.info("### SSO : Check point passed");
if (request.getServletPath().equals(SSOConstant.getREDIRECT_URL())) {
logger.info("### SSO : Check point passed, user trying access login form but already authenticated, redirect");
response.sendRedirect(request.getContextPath() + SSOConstant.getMAIN_URL());
return false;
}
}
}
return super.preHandle(request, response, handler);
}
}
and add this xml configuration to dispatcher-servlet.xml
<mvc:interceptors>
<bean class="ptpn4.rawi.sso.client.authentication.SSOInit" />
</mvc:interceptors>
In class SSOInit, I do some checking to database, I'm trying to build Custom SSO Solution.
I hope another better solution regarding my current approach.

Recording logins with Spring Security

I want to log every login in my web application. I was able to access the logins which take place through UsernamePasswordAuthenticationFilter but I don't know how to log users who log in using remember-me functionality. I tried overriding the
createSuccessfulAuthentication(HttpServletRequest request, UserDetails user)
of TokenBasedRememberMeServices, but then logouts are recorded too, because the remember-me service re-authenticates the user.
The best way of logging authentication success and failures is to use a Spring ApplicationListener.
Spring Security publishes various events for authentication success and failure which you can listen for. Events are also published when access is denied to a resource.
You can look at LoggerListener as an example. Start by adding one of those to your application context and it will automatically log authentication events at warn level.
Regarding remember-me logins, if you logout and then access the site immediately afterwards, and are re-authenticated using a remember-me cookie, then technically that is the same as any other remember-me authentication, so there's not much you can do about it.
However, if your logout success URL is passing through the remember-me filter, and that is how the new session is being created (without any additional action from the user), then simply omit it that page from the security filter chain.
For logging each sucessful login i think best way is to create LoginSucessHandler and specify authentication-success-handler for normal login as well as remember-me. i have done this with below code and configuration.
#Service
public class LoginSucessHandler extends
SavedRequestAwareAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
User user = (User) authentication.getPrincipal();
// record login success of user
super.onAuthenticationSuccess(request, response, authentication);
}
}
<http auto-config="true" use-expressions="true">
<form-login login-page="/login"
authentication-failure-url="/login.hst?error=true"
**authentication-success-handler-ref="loginSucessHandler"** />
<logout invalidate-session="true" logout-success-url="/home"
logout-url="/logout" />
<remember-me key="jbcp" **authentication-success-handler-ref="loginSucessHandler"**/>
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
</http>
I think in your case will help solution when you will use your custom filter, which will intercept every request to your application. In this filter you can log username for every request.
Here I described how to add your custom filter. You just need to change functionality to what you want. And don't forhet to put your filter after security filter chain in web.xml.

How to use J2eePreAuthenticatedProcessingFilter and a custom authentication provider?

I want my Spring application to try two pre-authentication methods (Siteminder and Java EE container authentication).
If either of these filters locates a username - I want to check that username against my database of users and assign roles based on what I see in the database. (I have an implementation of AuthenticationUserDetailsService, which does that for me.)
If not - show a login page to the user. Check the credentials they enter in the form against my database of users.
The Siteminder integration is working. The login form is working too. My problem is with the Java EE pre-authentication. It never kicks in.
My applicationContext-security.xml:
<!-- HTTP security configurations -->
<sec:http auto-config="true" use-expressions="true">
<sec:form-login login-processing-url="/resources/j_spring_security_check" always-use-default-target="true" default-target-url="/" login-page="/login"
authentication-failure-url="/login?login_error=t" />
<sec:logout logout-url="/resources/j_spring_security_logout" />
<sec:access-denied-handler error-page="/accessDenied" />
<sec:remember-me user-service-ref="customUserDetailsService" token-validity-seconds="86400" key="OptiVLM-VaultBalance" />
<sec:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter"/>
<sec:custom-filter after="PRE_AUTH_FILTER" ref="jeePreAuthenticatedFilter"/>
<!-- various intercept-url elements here, skipped for brevity -->
</sec:http>
<!-- Authentication Manager -->
<sec:authentication-manager alias="authenticationManager">
<!-- J2EE container pre-authentication or Siteminder -->
<sec:authentication-provider ref="customPreAuthenticatedAuthenticationProvider" />
<!-- Default provider -->
<sec:authentication-provider user-service-ref="customUserDetailsService" />
</sec:authentication-manager>
<!-- Siteminder pre-authentication -->
<bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="principalRequestHeader" value="SM_USER" />
<property name="authenticationManager" ref="authenticationManager" />
<property name="exceptionIfHeaderMissing" value="false" />
</bean>
<!-- J2EE pre-authentication -->
<bean id="jeePreAuthenticatedFilter" class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<!-- Custom pre-authentication provider -->
<bean id="customPreAuthenticatedAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" ref="customAuthenticationUserDetailsService" />
</bean>
I have Java 2 security enabled in Websphere, and I am logged in as 'admin5'. (I have a user with this username in my user database.) But when I access the application, there is never a call to the 'customAuthenticationUserDetailsService' bean to verify the username. I know this, because 'customAuthenticationUserDetailsService' does extensive logging which clearly shows what it is doing. When I am using the Siteminder pre-authentication - the 'customAuthenticationUserDetailsService' works just fine, I get some trace output in the log. But not for the J2EE authentication...
My guess is that one of these things is happening:
a) Java EE pre-authentication filter is not locating the username, so it never calls the authentication manager
b) Java EE pre-authentication filter works fine, but my custom authentication provider is never called by the authentication manager for some reason
By the way, the default authentication provider, which uses 'customUserDetailsService' does not kick in either. Again, I can tell that because there is no output from 'customUserDetailsService' in the log.
Can you advise on what could be the problem here? If not a solution, then a suggestion on how to approach this would be greatly appreciated.
OK, I figured this out. The problem is that even though I had J2EE security setup in Websphere and was authenticated, my web.xml contained no security constraints. Because of this, Websphere was not supplying the principal for my requests. This is apparently an intentional feature. If you are not accessing a protected URL, you should not need the pre-authentication information.
To overcome this, I added a security constraint to my web.xml, which allowed ALL users to access the resources. Effectively, the resources were not secured, but still - there was a constraint now.
This is it:
<security-constraint>
<web-resource-collection>
<web-resource-name>All areas</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
This tricks the Websphere into filling in the user principal information in the request.
Thank you #Ralph for his comments on this this question: request.getUserPrincipal() got null

Spring Security Remember me with custom authentication provider

I am using GWT with spring security. I have a custom authentication provider where I perform all my authentication. How can I configure the remember me feature without using the UserDetailsService? I am not using LDAP.
My AppliationContext_security.xml
<http auto-config="true" entry-point-ref="UnauthorizedEntryPoint"
create-session="always">
<form-login authentication-success-handler-ref="authenticationSuccessHandler"
authentication-failure-handler-ref="authenticationFailureHandler" />
<logout success-handler-ref="logoutSuccessHandler"
invalidate-session="true" />
<intercept-url pattern="/**/myapp.rpc" access="ROLE_USER" />
<custom-filter before="CONCURRENT_SESSION_FILTER" ref="XSRFAttackFilter" />
</http>
<authentication-manager>
<authentication-provider ref="myAuthenticationProvider" />
</authentication-manager>
In my custom authentication provider,
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
boolean response = loginmanager.authenticateUser(username, password,
((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest().getSession());
if (!response) {
throw new BadCredentialsException(
"Invalid Credentials.");
}
Authentication authentication = ...
authentication.setAuthenticated(true);
return authentication;
}
Any help will be greatly appreciated.
You will need to create a custom UserDetailsService that gets the username/password from the same place that your loginmanager is reading it from. See the source for TokenBasedRememberMeServices.processAutoLoginCookie() to see how it's being used.

Resources