Spring SecurityXML. http tag inheritance - spring

I have a security-spring.xml with some general rules applied for many urls and I want to make an exception for one specific url that also matches that pattern. Can I do it without copying the complete <http> tag?
What I tried is this:
<beans ...>
<http pattern="/a/b" xmlns="http://www.springframework.org/schema/security" >
<csrf disabled="true"/><!-- An exception I want to add -->
</http>
<http pattern="/a/**" xmlns="http://www.springframework.org/schema/security" ...someproperties >
<!-- General config for many urls -->
</http>
</beans>
Accessing /a/b without csrf token works but looks like it doesn't inherit any config properties from the /a/** pattern.
Is that how it's supposed to be (each http is independent) or is there a way to "append" this exception to /a/b and inherit the rest from the /a/**?
Spring-security version: 4.2.6

The <csrf> configuration element is a sub-element of the main container element for security configuration, i.e. the <http> element.
So yes, if you would like to have the Corss-site Request Forgery disabled / enabled for a configured sub-url, you have to duplicate all the necessary configuration elements.
One particular solution to avoid duplication would be to opt for a Java-based configuration.

Related

How to set up server.xml in WebSphere Liberty with LDAP to match global security active similar to WAS 7.0 for spring apps

I have a spring app.
It is consistently giving me this error in websphere liberty. This is my login settings .
in web.xml for spring security.
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<!-- ===== SECURITY CONFIGURATION ===== -->
<!-- All requests matching pattern below will bypass the security filter chain completely -->
<security:http pattern="/image/**" security="none"/>
<!-- security:http pattern="/login.jsp*" security="none" / -->
<!-- Defines who can access each URL. -->
<!--
Spring Security 3.0 introduced the ability to use Spring EL expressions as an authorization mechanism in addition to the simple use
of configuration attributes and access-decision voters which have seen before. Expression-based access control is built on the same
architecture but allows complicated boolean logic to be encapsulated in a single expression.
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/el-access.html
-->
<security:http auto-config="true" use-expressions="true">
<!-- URL restrictions (order is important!) Most specific matches should be at top -->
<!-- Don't set any role restrictions on login.jsp. Any requests for the login page should be available for anonymous users -->
<security:intercept-url pattern="/login.jsp*" access="isAuthenticated()" />
...
Anonymous access to the login page doesn't appear to be enabled. This is almost certainly an error. Please check your configuration allows unauthenticated access to the configured login page. (Simulated access was rejected: org.springframework.security.access.AccessDeniedException: Access is denied)
I have configured LDAP but I do not know how to tie LDAP settings to server authentication as similar to WAS 7.0 global security activation so the application is not able to authenticate .
Can someone give me further infomation as how the access-id in security settings relates to LDAP Realm.
<jaasLoginContextEntry id="system.WEB_INBOUND" loginModuleRef="HashLogin, certificate, hashtable, token, userNameAndPassword" name="system.WEB_INBOUND"/>
<jaasLoginContextEntry id="WSLogin" loginModuleRef="WSLoginId, certificate, hashtable, token, userNameAndPassword" name="WSLoginId" />
<jaasLoginModule id="WSLoginId" className="com.ibm.ws.security.common.auth.module.WSLoginModuleImpl" libraryRef="${com.ibm.ws.security.wim.*}"></jaasLoginModule>
</server>
I have looked at the Liberty profile documents so I would appreciate a more detailed information then linking me to IBM documents because I have read those and several information out in internet a lot and have exhausted all resources that I can do look up on so I would really appreciate a more detailed explanation which would explain how to implement global security and application security enablement as WAS 7.0 does when we configure LDAP repository in WAS . My LDAP is Microsoft Active Directory. And my application security is handled by spring container.
As resource I looked at this but this did not seem to help.
How to map security role to ldap group in websphere liberty profile
Here is how access-id in the Liberty profile can be defined assuming the LDAP server definition has realm name as ldapRealm in server.xml.
<!- Sample LDAP definition -->
<ldapRegistry id="TivoliLdap" host="myHost.rtp.raleigh.ibm.com" realm="ldapRealm" port="389" ldapType="IBM Tivoli Directory Server" ignoreCase="false" baseDN="o=mycompany,c=us">
</ldapRegistry>
<!-- Application binding sample for using access-id attribute for user or group element -->
<application-bnd>
<security-role name="Employee">
<user name="Bob" access-id="user:ldapRealm/Bob"/>
<group ame="developers" access-id="group:ldapRealm/developers"/>
</security-role>
</application-bnd>

Spring Security for RESTful API

I'm building a restful API using Spring 4.1.6 and spring-boot-starter-data-rest.
To make the rest api fully functional I need the last piece of the puzzle: security. Now I noticed spring has it's own spring-security-* packages that can aid with that task.
I tried using spring-security-config and spring-security-web and it works like a charm, with the exception that if the user is not authenticated, spring will redirect the user to login, thus giving a HTML login form.
Because it's a Restful API, I just need an error to be returned in a JSON object if the user lacks the credentials or does not have enough permissions to read a particular resource.
I'm sure I'm not the first to ask this question and searched all over the web for people asking the same thing, but couldn't quite find was I was looking for. So.. should I continue my research in this direction with spring-security, or should I find something?
Any advice is welcome,
thank you
To change the Login Form response to a custom Http Response you need to configure a custom http response handler for Http Security config. If you are using xml for your security configuration use the configuration shown below, failureHandler used is the one available in Spring Security package. Update the URL to match yours.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- Rest authentication entry point configuration -->
<http use-expressions="true" entry-point-ref="restAuthenticationEntryPoint">
<intercept-url pattern="/api/**" />
<sec:form-login authentication-failure-handler-ref="myFailureHandler" />
<logout />
</http>
<!-- Using default failure handler -->
<beans:bean id="myFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler" />
</beans:beans>

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.

Securing REST API with Spring Security

I'm trying to implement a REST API for my Spring application. As there are resources which might not be accessed by everyone, I need a security layer.
Within this application I'm already using Spring Security (which works perfectly fine) for securing my web application.
I've added the following http configuration to my spring-security.xml:
<http pattern = "/api/**" use-expressions = "true" disable-url-rewriting = "true">
<http-basic />
</http>
So I would assume that all request that are made to URLs starting with api/ will be secured.
Problem is that I can access my secured methods without any authentications. But if I use a REST client to access it, I receive this error:
message: Full authentication is required to access this resource
description: This request requires HTTP authentication.
I have no idea how to proceed. What is the best way to secure a REST API using Spring Security?
If you use Spring Security in your application, you, probably, already have an <http> section in one of your Spring config files. You can use this section to secure your REST API.
The <http> does not secure anything on its own. You have to add <intercept-url> rules inside it:
<intercept-url pattern="/api/**" access="hasRole('ROLE_USER')" />
There is a tuto on the official site of Spring. It is a little more complicated :
Official Spring Tuto
Just use Spring Security. In <http> tag add: <security:intercept-url pattern="your url" access="hasAnyRole('Your_User_Role1', 'Your_User_Role2')" />.
Or try use annotations. In your spring-config.xml enable security annotations: <security:global-method-security jsr250-annotations="enabled" pre-post-annotations="enabled" secured-annotations="enabled"/>
and in Controller add #PreAuthorize :
#PreAuthorize("hasAnyRole('Your_User_Role1', 'Your_User_Role2')")
#RequestMapping(value = "/address_planing/load_employee_info")

Why is my Spring PreAuthFilter always called?

I have my Spring 3.1 app configured like this
<http use-expressions="true" entry-point-ref="http401UnauthorizedEntryPoint">
<intercept-url pattern="/app/demo" access="hasRole('Demo')" />
<intercept-url pattern="/app/**" access="isAuthenticated()" />
<intercept-url pattern="/admin/**" access="hasRole('Admin')" />
<custom-filter position="PRE_AUTH_FILTER"
ref="currentWindowsIdentityAuthenticationFilter" />
<logout invalidate-session="true" delete-cookies="JSESSIONID"
logout-url="/logout" logout-success-url="/logout-success" />
</http>
I have written a custom preauth filter. When I call my app at the root URL / the filter chain hooks in and runs the preauth filter although this resouce is not protected. This means that the logout does not work as designed. After a logout a login is performed again.
My implementation is based on the org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter class.
Is this normal behavior or can this be fixed some how? I'd like the auth be performed on the protected URLs only.
As I side note, I do not intend to configure security='none' because I want to maintain the security context on all pages.
I have posted the appropriate log out on pastebin. It is too verbose to include in here.
Seems that what you want is creating special <http> without any filters for logout URL:
<http pattern="/logout/**" security="none" />
<http use-expressions="true" entry-point-ref="http401UnauthorizedEntryPoint">
<intercept-url pattern="/app/demo" access="hasRole('Demo')" />
<intercept-url pattern="/app/**" access="isAuthenticated()" />
<intercept-url pattern="/admin/**" access="hasRole('Admin')" />
<custom-filter position="PRE_AUTH_FILTER"
ref="currentWindowsIdentityAuthenticationFilter" />
<logout invalidate-session="true" delete-cookies="JSESSIONID"
logout-url="/logout" logout-success-url="/logout-success" />
</http>
Read more about request matching mechanism here.
EDIT:
#LukeTaylor mentioned that if you want to create another filter chain then the pattern should go in the element (is this documented somewhere explicitely?), so my idea with separate chain without PRE_AUTH_FILTER obviously won't work. Added <http> for /logout without any filters, which should prevent authorizing at logout requestes.
Still, I don't know how prevent requests like /other from applying PRE_AUTH_FILTER. One way could probably be abandon <http> namespace configuration to manual filterChainProxy configuration with two <sec:filter-chain> patterns, but I don't know if it's worth it.
#Michael-O: About exception IllegalArgumentException: A universal match pattern ('/**') is defined before other patterns - it's strange, is it your whole XML config for Security? Or maybe it's just a consequence of what Luke said (that another <http> element should have pattern)...
I was able to indentify the issue but it cannot be solved the way it is now because of the way the entire chain works.
Here's the deal:
When you define a <http> element on /** you ask Spring Security to fire the entire filter chain on all paths under your defined pattern. It does not matter whether one of them needs protection or not. Rob Winch published a very helpful video. If you take a closer look at the default filter stack you'll what filters are applied. Amidst these is my filter located.
The first ten lines of my log file reveal that the entire chain is fired since / matches the <http> configuration. At the end, the FilterSecurityInterceptor sees that this resource does not need protection. More over, you see that the CurrentWindowsIdentityAuthenticationFilter is fired too and performs unwanted authentication.
Why? Compared to header-based filters or URL processing filters you have no trigger/entry point to commence the authentication deliberately you simply do without challenging the client regardless the URL needs protection or not. Defining something like this <http pattern="/unprotected-url" security="none" /> saves you absolutely nothing because you lose the security context on unprotected paths. You want to keep your client logged in regardless of the URL protection.
How can this be solved now? You have two options:
Define a <http> element on /app/**, /admin/** so on but this is really cumbersome and contains repitions all over. I would not recommend such a solution. Additionally, you probably won't have the sec context on other URLs in /**. This is not desired.
Split the preauth filter in two filters:
CurrentWindowsIdentityPreAuthenticationFilter
CurrentWindowsIdentityUrlAuthenticationFilter
The second option solves the problem.
CurrentWindowsIdentityPreAuthenticationFilter: Remains as-is and peforms the auth always. Very helpful for M2M communication like script access or REST requests.
CurrentWindowsIdentityUrlAuthenticationFilter: Suits human interaction very well. It works basically like a form-based filter. If define a URL, say /login, you will get redirected to when you request a protected resource and after successful auto-auth you be redirected back to your actual resource. Auth is done. Public resources remain unauthenticated because the preauth filter is trigged on /login only just like form-based. If you log out you stay logged out.
I'd be happy if any of the Spring folks can confirm my analysis.

Resources