Spring LDAP Context.REFERRAL to follow - spring

How do I set the LDAP Context.REFERRAL to follow in a Spring Security configuration? This is related to a problem I already reported and for which I found an unsatisfactory solution before discovering the real solution I am seeking for involve setting this environment attribute in the LDAP context to follow the referral for the ActiveDirectoryLdapAuthenticationProvider.
Here is the reference to my original question: Spring Security 4.0.0 + ActiveDirectoryLdapAuthenticationProvider + BadCredentialsException PartialResultException
Addendum: It seems no one is having such an environment here. Despite the silence on this problem, I post here my configuration hoping someone will be able to help me with this. I just don't know what I should do to solve this problem.
Here are the error messages in my log:
2015-06-15 10:32:19,810 DEBUG (o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter) [http-8443-1] /identite.proc at position 7 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2015-06-15 10:32:19,810 DEBUG (o.s.s.w.u.m.AntPathRequestMatcher.matches) [http-8443-1] Checking match of request : '/identite.proc'; against '/identite.proc'
2015-06-15 10:32:19,810 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.doFilter) [http-8443-1] Request is to process authentication
2015-06-15 10:32:19,811 DEBUG (o.s.s.a.ProviderManager.authenticate) [http-8443-1] Authentication attempt using org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider
2015-06-15 10:32:19,811 DEBUG (o.s.s.l.a.AbstractLdapAuthenticationProvider.authenticate) [http-8443-1] Processing authentication request for user: myusername
2015-06-15 10:32:19,841 DEBUG (o.s.s.l.SpringSecurityLdapTemplate.searchForSingleEntryInternal) [http-8443-1] Searching for entry under DN '', base = 'dc=dept,dc=company,dc=com', filter = '(&(userPrincipalName={0})(objectClass=user)(objectCategory=inetOrgPerson))'
2015-06-15 10:32:19,842 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-1] Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2015-06-15 10:32:19,842 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-1] Updated SecurityContextHolder to contain null Authentication
2015-06-15 10:32:19,842 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-1] Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler#a5d7f2
And here is the configuration:
<b:bean id="monFournisseurAD" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<b:constructor-arg value="dept.company.com" />
<b:constructor-arg value="ldap://dept.company.com:3268/" />
<b:constructor-arg value="dc=dept,dc=company,dc=com" />
<b:property name="searchFilter" value="(&(userPrincipalName={0})(objectClass=user)(objectCategory=inetOrgPerson))" />
<b:property name="userDetailsContextMapper">
<b:bean class="org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper" />
</b:property>
<b:property name="authoritiesMapper" ref="grantedAuthoritiesMapper" />
<b:property name="convertSubErrorCodesToExceptions" value="true" />
</b:bean>
<b:bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<b:constructor-arg value="ldap://dept.company.com:3268/dc=dept,dc=company,dc=com" />
<b:property name="baseEnvironmentProperties">
<b:map>
<b:entry key="java.naming.referral" value="follow" />
</b:map>
</b:property>
</b:bean>
<b:bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<b:constructor-arg ref="contextSource" />
</b:bean>
<b:bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />
<b:bean id="myDeconnexionHandler" class="com.company.dept.web.my.DeconnexionHandler" />
The two beans with ids contextSource and ldapTemplate seems not to change anything. I was trying to get the referral follow behavior. It seems not the right way to configure it. Also, here the port in the ldap URL is set to 3268 because it is the general catalog and someone in another description elsewhere suggested to use it. But, the results are exactly the same with port 389.
If I change the first constructor argument in the bean monFournisseurAD to set it to a single userPrincipalName domain, it will work for all users into that domain. While I can actually authenticate anyone from the command line using ldapsearch command using dept.company.com instead of the userPrincipalName domain associated directly to the user. In fact, if I enter a wrong password, I will get the specific wrong password message. This seems to prove the user is actually authenticated by AD/LDAP, however Spring fails later to fetch the attributes for that user.
How can I solve this problem?

Finally, the only way to solve this problem is to modify the code since the method org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.searchForUser() is wired to pass the bindPrincipal to SpringSecurityLdapTemplate.searchForSingleEntryInternal() which actually recover the record for the user using the search filter defined in the XML or set with setSearchFilter(). Since the bindPrincipal is actually the username#domain, this value is not suitable for sAMAccountName usage in the search filter, it will always fail. Since the bind to the Active Directory server is performed using the userPrincipalName and then the bindPrincipal you have no way to specify to searchForUser() it must use the username only in the search rather than the bindPrincipal (UPN). I fixed my problem by copying the whole class org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider in my package and modify the searchForUser() method to pass the username instead of the bindPrincipal to the method searchForSingleEntryInternal(). This works, but it is still a wired/hardcoded solution. A more elegant solution would be to introduce a list of patterns and a method to compose the values for the call to searchForSingleEntryInternal() or a method that would detect the kind of arguments required from the searchFilter() string.

Related

Spring 4.3.25.RELEASE OAuth2 Configuration Problem

I am working on a system that uses Spring 4.3.25.RELEASE and xml based configuration. I need to integrate with another system using OAuth2, and therefore trying to configure the system as an OAuth2 Client, but it's proving difficult to find examples and documentation.
I can redirect to the IdP ok, but on return I am seeing this error:
Possible CSRF detected - state parameter was required but no state
could be found
This is the configuration I have in place, which is obviously incomplete. Can you please help me identify what is missing?
Thanks.
<custom-filter ref="oauth2ClientFilter" after="EXCEPTION_TRANSLATION_FILTER"/>
<custom-filter ref="oauth2AuthenticationFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
...
<oauth:client id="oauth2ClientFilter" />
<beans:bean id="oauth2AuthenticationFilter" class="org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter">
<beans:constructor-arg name="defaultFilterProcessesUrl" value="/oauth2/callback"/>
<beans:property name="restTemplate" ref="restTemplate"/>
</beans:bean>
<oauth:rest-template id="restTemplate" resource="oauth2Token"/>
<oauth:resource id="oauth2Token"
type="authorization_code"
client-id="my-client-id"
client-secret="my-client-secret"
access-token-uri="https://http://myurl/token"
user-authorization-uri="http://myurl/authorize"/>

Spring Security - Is SavedRequestAwareAuthenticationSuccessHandler broke?

TLDR: Spring is destroying the current HTTP session when redirecting to the login page; this destroys the ability to navigate to the DefaultSavedRequest after login. Why is this happening?
Details -
I am maintaining a legacy Spring application:
Spring Core version 3.1.0
Spring Security version 3.1.0
When trying to utilize SavedRequestAwareAuthenticationSuccessHandler in my login configuration, it is not working. Here is what seems to be happening:
HTTP GET to secured resource: http://localhost:8080/myapp/viewWorkOrder?workOrderNumber=315261
Spring correctly determines that I am not logged in and saves my request:
DEBUG o.s.s.w.s.HttpSessionRequestCache - DefaultSavedRequest added to Session: DefaultSavedRequest[http://localhost:8080/myapp/viewWorkOrder?workOrderNumber=315261]
Spring correctly redirects to my login page:
DEBUG o.s.security.web.FilterChainProxy - /login.jsp at position 1 of 9 in additional filter chain; firing Filter: 'ChannelProcessingFilter'
Spring destroys the current session which effectively destroys the ability to later use the DefaultSavedRequest:
DEBUG o.s.s.w.s.HttpSessionEventPublisher - Publishing event: org.springframework.security.web.session.HttpSessionDestroyedEvent[source=org.apache.catalina.session.StandardSessionFacade#b25f027]
Why or what is causing the current session to be destroyed?
Here are the pertinent configuration details:
<bean id="savedRequestAwareAuthenticationSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/postLogin" />
<property name="targetUrlParameter" value="targetUrl" />
<property name="alwaysUseDefaultTargetUrl" value="false" />
</bean>
<security:http auto-config="false">
<!-- Override default login and logout pages -->
<security:form-login login-page="/login.jsp"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/login.jsp?login_error=1"
authentication-success-handler-ref="savedRequestAwareAuthenticationSuccessHandler"
/>
<security:session-management session-fixation-protection="none"/>
Note that the inclusion of session-management does not seem to affect the feature either way.
Well, this is embarrassing but in the interest of being a good citizen on stack overflow I thought I would share what I found.
After setting a breakpoint in the Spring HttpSessionEventPublisher to see if the stack might give me a clue, it certainly did. Here is a screenshot:
You'll notice that login.jsp is on the stack. Being new to this particular application, I hadn't really even suspected the JSP but here is what I found:
Obviously, removing this scriptlet solved my issue. Now I just wonder why someone did it and what I broke in the process :)

How can I use basic authentication and form based authentication spring security

So I am looking for a programmatic configuration way of using form based authentication and basic authentication on the same resource. What I mean is if I fill out the login form and authenticate I should be able to use the site. At the same time if I authentication using basic auth I should be able to access the same resources. Is it possible? I was even thinking maybe using a DelegatingAuthenticationEntryPoint where if there is a certain header specified it will use basic otherwise it will use form based login. Anyway any help would be appreciated?
I think you should look at the request-matcher-ref attribute of the http element in the Spring Security Current Reference Documentation. It enables you to specify custom conditions under which a particular FilterChain will be used or not. For example, you can determine which authentication mechanism to use, according to the host header of incoming request.
<bean id="customMatcher1" class="org.springframework.security.web.util.matcher.ELRequestMatcher">
<constructor-arg value="hasHeader('host', 'stackoverflow.com')"/>
</bean>
<bean id="customMatcher2" class="org.springframework.security.web.util.matcher.ELRequestMatcher">
<constructor-arg value="hasHeader('host', 'careers.stackoverflow.com')"/>
</bean>
<sec:http request-matcher-ref="customMatcher1">
<sec:http-basic />
</sec:http>
<sec:http request-matcher-ref="customMatcher2">
<sec:form-login />
</sec:http>
Look and choose one of existing implementations or look and write own implementation of the RequestMatcher interface.

Basic Authentication Filter and authentication entry point not actually used from spring oauth2 token request

I have implemented resource owner flow with spring oauth2 based on spring's sparklr sample application and a couple of samples I found online. I tested the token request part with curl like this in order to provide both client and user credentials:
curl -v --data "username=user1&password=user1&client_id=client1&client_secret=client1&grant_type=password" -X POST "http://localhost:8080/samplerestspringoauth2/oauth/token"
and it works correctly, however I have made the following observation:
Although according to the examples I saw, I make use of the BasicAuthentication filter, this is not really used in the security process. Since the token request does not contain an Authentication header, the BasicAuthentication filter just skips doing any checks. ClientCredentialsTokenEndpointFilter and authentication-server are the only ones performing security checks during the token request. After noticing this and verifying it via debugging, I tried to remove completely the following part:
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
from the configuration. But then I got the warning:
"No AuthenticationEntryPoint could be established. Please make sure
you have a login mechanism configured through the namespace (such as
form-login) or specify a custom AuthenticationEntryPoint with the
'entry-point-ref' attribute".
As a next step, I added the entry-point-ref="clientAuthenticationEntryPoint in the http namespace, and got rid of the warning. I tested the app and played correctly.
However, in addition to the above, I have also made the following observation during debugging:
The ClientCredentialsTokenEndpointFilter, contains its own OAuth2AuthenticationEntryPoint entry point inside a private variable, and uses that when failing due to wrong client credentials.
Therefore, it does not matter what entry point I specify either in the basic filter, or in the http namespace. At the end ClientCredentialsTokenEndpointFilter will use its own private OAuth2AuthenticationEntryPoint.
To summarize my conclusions seem to be the following:
The basic filter is not used and can be removed, if we specify the
endpoint in the http namespace instead.
Specifying either a basic
filter,or an endpoint in http namespace is needed only for the
compiler to stop the warning. They have no practical use, and the
endpoint used is hardcoded inside
ClientCredentialsTokenEndpointFilter.
Below I put the http and endpoint configuration for the token request for your reference. I skip the rest of configuration for keeping the post easy to read:
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<custom-filter ref="clientCredentialsTokenEndpointFilter"
before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="springsec/client" />
<property name="typeName" value="Basic" />
</bean>
I also assume that the same issue also occurs in the original sparklr application (which is spring oauth2 sample app) configuration for token request which is very similar. That can be found in https://github.com/spring-projects/spring-security-oauth/blob/master/samples/oauth2/sparklr/src/main/webapp/WEB-INF/spring-servlet.xml, and the related part is below:
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/**" method="GET" access="ROLE_DENY" />
<intercept-url pattern="/**" method="PUT" access="ROLE_DENY" />
<intercept-url pattern="/**" method="DELETE" access="ROLE_DENY" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request
parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter"
after="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
I would expect spring oauth2 to more appropriately interact with spring security instead of having to put unnecessary and misleading configuration, and that makes me think that I may have missed something. Since security is a sensitive aspect I wanted to share that with you and ask if my conclusion correct.
The /oauth/token provides two different ways to authenticate clients which are requesting tokens:
Using HTTP-Basic authentication (when "http-basic" element is present)
The authentication is handled with org.springframework.security.web.authentication.www.BasicAuthenticationFilter and processes the "Authorization" HTTP header which contains base64 encoded credentials of the client. The filter only performs processing when the Authorization header is present. This method is always tried first. The entry point defined on http-basic will only be invoked when user has supplied an "Authorization" header with invalid content - that's why you don't see the entry point invoked in your debugger, try to set an Authorization HTTP header and your breakpoint will get a hit.
As defined in the OAuth standard using client_id and client_secret HTTP paremeters
This is handled using org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter and by default uses entry point which sends back WWW-Authenticate header to the client. The default entry point can be customized (there's a setAuthenticationEntryPoint method). The entry point is only used when you supply client_id parameter.
Both of these methods use different ways to obtain client's username+password, but verify it against the same authentication manager.
The "No AuthenticationEntryPoint could be established" error which you observe when taking out the <http-basic> element is coming from Spring Security itself, not from the OAuth Extension. The reason is that Spring Security is not able to tell that there's a default entry point already configured inside of the custom filter ClientCredentialsTokenEndpointFilter. And the HTTP configuration of Spring Security always must have at least one entry point available.
So, the complete logic goes as follows:
when you include "Authorization" header with invalid credentials and <http-basic> element is present , system will use entry point defined on the <http-basic> element. If none is specified (attribute entry-point-ref is missing), system will create a default instance of BasicAuthenticationEntryPoint automatically for you and use it.
when you include HTTP parameter "client_id" and "client_secret" with invalid credentials and custom filter clientCredentialsTokenEndpointFilter is present, system will use entry point defined in the clientCredentialsTokenEndpointFilter bean (which is by default instance of OAuth2AuthenticationEntryPoint)
in case neither "Authorization" header nor "client_id" parameter are present and the endpoint requires authentication ("IS_AUTHENTICATED_FULLY"), system will use the entry point defined on the <http entry-point-ref="">, if present, otherwise it will use the entry point defined on the http-basic (as above)
in case you don't specify neither http-basic (or other default authentication method which Spring recognizes), nor default entry point using the <http entry-point-ref="">, system will fail with "No AuthenticationEntryPoint could be established", because it requires at least one entry point and it doesn't understand that there's one available inside the clientCredentialsTokenEndpointFilter.
Regarding your observations:
>> The basic filter is not used and can be removed, if we specify the
endpoint in the http namespace instead.
> This is true in case you are authentication your clients using client_id + client_secret
>> Specifying either a basic filter,or an endpoint in http namespace is
needed only for the compiler to stop the warning. They have no
practical use, and the endpoint used is hardcoded inside
ClientCredentialsTokenEndpointFilter.
> Partly true, as the entry point will be used in case client_id is missing.
The configuration is indeed confusing (which is partly caused by the fact that OAuth isn't a native part of Spring Security, but an extension), but all of those settings make sense and are used in specific situations.
The changes you made have no security implications.

spring security - custom filter positioning

I need to customize my authentication process in such manner:
Client sends request (REST API) with a "special" URL param
Server calls third-party service passing a param and receiving user name
Server lookups database by name and this is authenticated principal.
I split my server side (2+3) on two parts - custom filter for (2), that obtains user name - and a custom userdetailservice for(3) that builds principal by looking up name in database.
But I cannot build my security.xml correctly - every time it seems that it doesn't process filter at all. I think the problem is in the first (http) node, but I cannot understand what position should I set up for filter. Here is my config:
<http use-expressions="true" auto-config="true" authentication-manager-ref="authenticationManager">
<intercept-url pattern="/*" access="isAuthenticated" />
<custom-filter ref="casServiceTicketFilter" position="FIRST"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="wliAuthenticationService"/>
</authentication-manager>
<b:bean id="casServiceTicketFilter" class="org.WLICASAuthenticationFilter">
<b:property name="casTicketValidateURL" value="${cas.ticket.validate.url}"/>
<b:property name="authenticationManager" ref="authenticationManager"/>
</b:bean>
<b:bean id="wliAuthenticationService" class="org.WLIUserDetailService"/>
PS- Please don't tell me that Spring has CAS support out-of-the-box. It's a bit various configuration so I need to create my own implementation of service ticket validator
Your custom authentication filter shouldn't be first in the filter chain. It needs to come after the SecurityContextPersistenceFilter. Use
<custom-filter ref="casServiceTicketFilter" after="SECURITY_CONTEXT_FILTER"/>
instead.
If you enable debug logging, you should be able to see clearly what order the filters are called in for each request and whether yours is invoked.

Resources