I'm making a Spring MVC web-app with some RESTfull resources as an API.
I need the RESTfull part to have some custom filters as I do not want any redirection and I want any exception to be translated with the corresponding HTTP error code and a basic JSON description.
On the other hand, the rest of the website have to be more common and redirect people when they are not logged in etc.
One more thing, I wish to use the #Secured annotations and a post-authentication in some case.
How do I define the multiple http namespaces correctly (on Spring 3.1)?
Here is my erroneous configuration:
<global-method-security secured-annotations="enabled" />
<http pattern="/rest/**" authentication-manager-ref="authenticationManager" entry-point-ref="restAuthenticationEntryPoint">
<form-login login-page="/rest/login" login-processing-url="/rest/postlogin"
authentication-success-handler-ref="restAuthenticationSuccessHandler"
authentication-failure-handler-ref="restAuthenticationFailureHandler"
username-parameter="username" password-parameter="password" />
<logout logout-url="/rest/logout" invalidate-session="true" />
</http>
<http pattern="/**" authentication-manager-ref="authenticationManager">
<form-login login-page="/login" login-processing-url="/postlogin"
username-parameter="username" password-parameter="password" />
<logout />
</http>
The funny part is that this configuration works partially as I can login with /rest/login and I get the response from my custom success handler. I can also login from /login and I get the proper redirection to /. The logout are working both fine too.
Next, all the controllers beans have #Secured("ROLE_USER") in the secured methods. But all the secured methods don't ever get secured. Why is that so?
#Secured({"ROLE_USER"})
#RequestMapping(method = RequestMethod.GET, headers = { "Range" })
public #ResponseBody
HttpEntity<List<T>> list(#RequestHeader("Range") String range) {
I've read documentations everywhere and I'm more confused than ever.
Why are my methods not being secured?
Must the http namespace define an access so that the #Secured annotations work?
Are the http namespace overwriting my #Secured annotations? If it's so, how can I define multiple "login pages" with custom filters and being able to use annotations?
Here are some facts:
* I'm using Spring and SpringSecurity 3.1
* I have a custom AuthenticationManager to retrieve user details from hibernate daos.
* Some controllers are extending an abstract class where the #Secured annotations lies. But it still doesn't work for a simple controller.
* My controllers are discovered with a context:component-scan and a base-package.
* The security works fine with one http namespace.
please help, i'm getting mad with this!
Check out this answer about making sure the web context is visible to the global-method-security declaration and possibly using class proxying.
To answer your other questions, no the http namespace shouldn't affect the use of #Secured annotations, other than that the user is authenticated by the web part of the application and that information will be used by the method security interceptor when making an access decision. Unless you override it (using access-decision-manager-ref), method security will use a standard AccessDecisionManager which grants or denies access based on the roles a user has.
Related
Greeting everyone, I try to configure simple authorization code flow via Spring Security OAuth.
I tested my authorisation and resource server configuration via following approaches:
Create a web application as client and use its page to fire http post call to /oauth/authorize.
After getting code, I use the same page to
fire another http post with code and get token.
At the end, I use
curl -H to place token inside header and get response from protected
resource.
But when I try to use rest template. It throw error message 401 Unauthorised error.
Server side - security configure:
<http auto-config="true" pattern="/protected/**"
authentication-manager-ref="authenticationManager">
<custom-filter ref="resourceFilter" before="PRE_AUTH_FILTER" />
<csrf disabled="true" />
</http>
<http auto-config="true">
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<form-login default-target-url="/admin.html" />
<logout logout-success-url="/welcome.html" logout-url="/logout"/>
<csrf disabled="true" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="admin" password="123456" authorities="ROLE_USER,ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
Server side - authorisation and resource configure:
<oauth:authorization-server
client-details-service-ref="clientDetails" error-page="error">
<oauth:authorization-code />
</oauth:authorization-server>
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="admin" secret="fooSecret" />
</oauth:client-details-service>
<oauth:resource-server id="resourceFilter" />
Client Side:
<oauth:client id="oauth2ClientContextFilter" />
<oauth:resource id="sso" client-id="admin"
access-token-uri="http://localhost:8080/tough/oauth/token"
user-authorization-uri="http://localhost:8080/tough/oauth/authorize"
use-current-uri="true" client-secret="secret"
client-authentication-scheme="header" type="authorization_code"
scope="trust" />
<oauth:rest-template id="template" resource="sso"/>
If anyone knows where goes wrong, please do let me know.
There were two issues with my configuration above.
I noticed my client used wrong secret to communicate with authorization server.
Token endpoint at authorization server use authentication manager which
serve user authentication. It result
client are rejected all times until I create new security realm for
token endpoint and configure it to use a authentication manger designed for
client.
Note client is different from user. Client is third party want to access resource belong to your user (also called resource owner).
I had the same problem. It helped to add a
org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService
to spring securities authentication-manager, glueing the clientDetailsService to the authentication manager. So
<authentication-manager alias="authenticationManager">
...
<authentication-provider user-service-ref="clientDetailsUserDetailsService"/>
...
</authentication-manager>
nearly solved the problem for me. I had one more Issue: Since ClientDetailsUserDetailsService has no default constructor, spring threw Exceptions of the form
org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class
[class org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService]:
Common causes of this problem include using a final class or a non-visible class;
nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
Which I could not solve without using a copy of that class receiving the clientDetailsService as property instead of a constructor arg.
I am using Spring Security 3.2.3 in my Spring MVC application and getting some unexpected behavior.
According to the documentation here, it should be possible to use ${_csrf.token} in the meta tags of my html:
<meta name="_csrf" content="${_csrf.token}" />
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}" />
From where I extract the value of "content" using JQuery and place it into the Request Header using AJAX.
For some reason though, Spring Security doesn't "convert" this into an actual token, it just gets sent into the header as a literal string "${_csrf.token}".
Trying the alternate route of using ${_csrf.token} in a hidden input according to the documentation, I then tried to check what the token evaluates to by checking the input's value, but it's still just plain text "${_csrf.token}".
Since it seems that Spring Security isn't in effect, am I missing some kind of configuration? I am currently using a barebones Spring Security Java configuration (as opposed to xml) as shown here:
import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.*;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf();
}
}
I know configure is getting called since I put a debug statement in it, so I assume that CSRF protection is indeed enabled since it should be by default.
I realize that the syntax "${}" is JSP Expression Language, and I am currently successfully using it to evaluate the context into an object with Thymeleaf, for example:
th:object="${context}"
So I tried adding "th:" in front of the meta tag's "content" like so:
<meta name="_csrf" th:content="${_csrf.token}"/>
But it results in an exception that this cannot be evaluated:
Exception evaluating SpringEL expression: "_csrf.token"
I think the key here may be figuring out how to get the expression to evaluate properly in my view.
I finally solved this problem, but it basically required rewriting Spring Security. Here it is in all its glory.
First, I followed the suggestions in Eyal Lupu's great blog post here, but I had to tweak it to my situation because of my AJAX requirement.
As for the Thymeleaf situation, the key tidbit is hidden away in the archives of the Thymeleaf forums - Infamous Issue 7.
https://github.com/thymeleaf/thymeleaf-spring/issues/7#issuecomment-27643488
The last comment by the creator of Thymeleaf himself says that:
th:action ... detects when this attribute is being applied on a
tag --which should be the only place, anyway--, and in such case
calls RequestDataValueProcessor.getExtraHiddenFields(... ) and adds the
returned hidden fields just before the closing tag.
That was the key phrase I needed to get the token to work. Unfortunately it's completely not obvious why th:action would also kick off getExtraHiddenFields, but at any rate it does, and that's what matters.
So for anyone struggling with Thymeleaf + Spring Security CSRF + AJAX POST, here are my steps (this is paring it down quite a bit but these are the high-level concepts to solve it):
Implement the Spring interface RequestDataValueProcessor and register it in Spring Security's XML config so you can override the method getExtraHiddenFields, which allows you to insert a hidden input field into the HTML (with the token of course). The token itself is generated with a Java.Util UUID.
With JQuery, read the value from that hidden field and set the Request Header's "X-CSRF-Token" attribute so that it gets sent over HTTP. It's not possible to simply leave the token in the hidden input field because we are not doing a form Submit, instead we use AJAX POST to call methods on the server side.
Extend Spring's HandlerInterceptorAdapter and register it as an interceptor so that every time a POST method is done, the "preHandle" method on the server side is called so it can compare the request token (extracted from the HTTP header in the previous step) to the session's token (should be the same!). After it does this check, it can either allow the request to go through or return an error.
I started with the same source article as you, I think, and the same "you should be able to" add answers as you did. I fought it a different way. I made Thymeleaf give me the answer I wanted.
<meta name="_csrf" th:content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
Thymeleaf put the attribute "content" with the requested Spring EL contents. I then used the provided JavaScript/JQuery to extract the info from the meta tags straight into the CSRF header.
Before adding the thymeleaf-extras-springsecurity namespace and its dependency into my project, I had similar problems. I never did get the meta tags to work, even with thymeleaf-extras-springsecurity. But I did successfully retrieve Spring Security's csrf token using the hidden input. I have instructions below that work for me:
In the html tag, add:
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
In your pom.xml (if you're using Maven) you'll need to add the dependency: thymeleaf-extras-springsecurity4.
Then add the hidden input inside your page's body to retrieve the csrf token.
<input type="hidden" id= "csrf-token" th:name="${_csrf.parameterName}" th:content="${_csrf.token}" />
and then use that within your javascript/jquery as follows:
function f1() {
var token1 = $('input#csrf-token').attr("content");
...
$.ajax({
...
type: "POST",
beforeSend: function (request)
{
request.setRequestHeader("X-CSRF-TOKEN", token1);
},
...
This all assumes that you have spring security enabled, and that you have NOT turned off csrf protection.
You have incorrect configuration for springSecurityFilterChain in your web.xml. Correct definition is:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
Spring Security uses set of servlet filters to provide the functionality it is offering (including CSRF protection). These filters are defined as Spring beans (i.e. they are instantiated and managed by Spring application context). DelegatingFilterProxy is a special type of servlet filter, which finds root application context on the registered servlet context and delegates every call to the same named bean.
Your issue is a different one, just stumbled across this one as well and it took me several hours to figure out the cause. The cause for the issue described by you is that you did not enable csrf support within your spring-security.xml
This little snippet needs to go into your security-config.xml:
<!-- Static resources such as CSS and JS files are ignored by Spring Security -->
<security:http pattern="/static/**" security="none" />
<security:http use-expressions="true">
<!-- Enables Spring Security CSRF protection -->
<security:csrf/>
<!-- Configures the form login -->
<security:form-login
login-page="/login"
login-processing-url="/login/authenticate"
authentication-failure-url="/login?error=bad_credentials"
username-parameter="username"
password-parameter="password"/>
<!-- Configures the logout function -->
<security:logout
logout-url="/logout"
logout-success-url="/login"
delete-cookies="JESSIONID"/>
<!-- Anyone can access these urls -->
<security:intercept-url pattern="/auth/**" access="permitAll"/>
<security:intercept-url pattern="/login" access="permitAll"/>
<security:intercept-url pattern="/signin/**" access="permitAll"/>
<security:intercept-url pattern="/signup/**" access="permitAll"/>
<security:intercept-url pattern="/user/register/**" access="permitAll"/>
<!-- The rest of our application is protected. -->
<security:intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<!-- Adds social authentication filter to the Spring Security filter chain. -->
<security:custom-filter ref="socialAuthenticationFilter" before="PRE_AUTH_FILTER" />
</security:http>
....
...
..
.
Save time by configuring this correctly...
Cheerio,
Flo!
In case you don't need to use Thymeleaf, I'd suggest the following:
Add this to the top of your page:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
Add this to your login form:
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
Add these dependencies to your pom.xml:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
After struggling a lot, that worked for me.
I would like to block the access to certain URLs in my spring web application. I did some research and came across "headers". I don't know how to use them though. Any help will be highly appreciated. Thanks in advance.
One of the most simple way to do this, which I can think of instantly, is to have a pre-defined list of blocked urls and check the request URL against this list in the overridden requiresAuthentication() method of your implementation of AbstractAuthenticationProcessingFilter.
#Override
protected boolean requiresAuthentication(final HttpServletRequest request, final HttpServletResponse response) {
List<String> blockedUrls = new Arraylist<>();
list.add("/foo/");
if(blockedUrls.contains(request.getRequestURI())) {
// go to blocked error page
} else {
// process the request normally
}
}
Shishir
How is your spring security configured? can you show us the code/xml?
Assuming you have configured spring-security with your webapp then it is easy to restrict URLs (including role based restrictions).
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/restricted/**" access="isAuthenticated()" />
<intercept-url pattern="/**" access="permitAll" />
<form-login login-processing-url="/loginProcess"
login-page="/"
authentication-failure-url="/?loginFailure=true"/>
<logout logout-url="/static/j_spring_security_logout"/>
</http>
The intercept-url elements define URL patterns and whether anyone/everyone can access that pattern. Spring will match from the top, so the most specific authentication should be at the top of the list. Also, in the above example, as the final entry matches all URLs, this means anything not specified in other URL patterns will be open.
Taken from this article - it also shows how to achieve the same using code config rather than in xml: http://automateddeveloper.blogspot.co.uk/2014/02/spring-4-xml-to-annotation-configuration.html
I have a web site hosted in IIS that uses Windows Authentication and exposes WCF web services.
I configure this service with an endpoint behavior:
<serviceAuthorization principalPermissionMode ="UseAspNetRoles"
roleProviderName="MyRoleProvider"/>
and a binding:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" />
</security>
When the service is called, Thread.CurrentPrincipal is set to a RolePrincipal with the client's Windows identity and roles provided by by configured provider.
All is well with the world.
Now I've added some additional WCF services that are consumed by REST-ful Ajax calls: Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" in the svc file, WebGet attribute in the service contract, and the AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed) attribute on the service implementation.
I also add the following incantation to web.config as recommended in MSDN:
<system.serviceModel>
...
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
...
</system.serviceModel>
My Ajax service almost works the way I want it to. When it's called, HttpContext.Current.User is set to a RolePrincipal with the roles I expect. But Thread.CurrentPrincipal remains set to an unauthenticated GenericPrincipal.
So I need to add a line of code to each of my service methods:
Thread.CurrentPrincipal = HttpContext.Current.User
Is there any incantation in the configuration file I can use to get Thread.CurrentPrincipal to be set automagically, like it is for a normal SOAP service?
UPDATE
Here's a blog from someone who had the same problem, and solved it by implementing custom behaviors. Surely there's a way to do this out of the box?
UPDATE 2
Coming back to add a bounty to this as it's bugging me again in a new project, using a WCF WebGet-enabled service on .NET 3.5.
I've experimented with a number of options, including setting principalPermissionMode="None", but nothing works. Here's what happens:
I navigate to a WebGet URL that calls my service: http://myserver/MyService.svc/...
I've put a breakpoint in Global.asax "Application_AuthorizeRequest". When this breakpoint is hit, both "HttpContext.Current.User" and "Thread.CurrentPrincipal" have been set to a "RolePrincipal" that uses my configured ASP.NET RoleProvider. This is the behavior I want.
I have a second breakpoint when my service's OperationContract method is called. When this breakpoint is hit, HttpContext.Current.User still references my RolePrincipal, but Thread.CurrentPrincipal has been changed to a GenericPrincipal. Aaargh.
I've seen suggestions to implement a custom IAuthorizationPolicy, and will look into that if I don't find a better solution, but why should I need to implement a custom policy to make use of existing ASP.NET authorization functionality? If I have principalPermissionMode = "UseAspNetRoles", surely WCF should know what I want?
This is an interesting question. I don't have the same setup as you, so its difficult to test whether my recommendations will apply exactly to your use case, but I can share what has worked for us with similar projects.
How we keep Thread.CurrentPrincipal and HttpContext.Current.User in Sync
We wrote an HttpModule called "AuthenticationModule" which inherits from IHtppModule.
We then attached to the HttpApplication.AuthenticateRequest event which happens very early in request lifecycle.
In our AuthenticateRequest event handler, we implement our application specific requirements including setting Thread.CurrentPrincipal and if necessary also the current context user. In this way you only implement this code once for your entire application and if it changes (like if you implement a custom Principal IIDentity) you have only one place to change it. (Don't duplicate this code in every service method.)
public class AuthenticationModule : IHttpModule
{
public void Dispose() { return; }
public void Init(HttpApplication app)
{
app.AuthenticateRequest += new EventHandler(app_AuthenticateRequest);
}
void app_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
// This is what you were asking for, but hey you
// could change this behavior easily.
Thread.CurrentPrincipal = app.Context.User;
}
}
Ours is actually a bit more complex as we implement a custom IIdentity, create an instance of GenericPrincipal and then assign it to both app.Context.User and Thread.CurrentPrincipal; but, the above is what you were asking for.
Don't forget to register your new HttpModule in your web.config!
For integrated app pools:
<system.webServer>
<modules>
<add name="AuthenticationModule" type="YourNameSpace.AuthenticationModule" preCondition="integratedMode" />
</modules>
</system.webServer>
For old classic app pools you'd have to put it in <system.web><httpModules></httpModules></system.web>
You might need to play with what goes inside that AuthenticationRequest event handler and/or the order with which you register the handler. Because ours is totally custom it might be different than what you need. We actually grab the Forms Authentication cookie, decrypt it, etc... you might need to ping some built in methods for WindowsAuthentication.
I believe this is a more generic way to handle your application authentication stuff as it applies to all HttpRequests whether that be a page request, an IHttpHandler, some 3rd party component, etc... That will keep it consistent throughout your app.
I'm not sure. Maybe this will help
<configuration>
<system.web>
<identity impersonate="true" />
</system.web>
</configuration>
http://msdn.microsoft.com/en-us/library/134ec8tc(v=vs.80).aspx
I have a web application secured with spring security (Spring 3.1.0). Now if a customer wants to register to my service, Spring Security say "No". This makes sense because the user is not yet authorized.
The controller, which gets the register data is a spring mvc controller. I need to exclude this from spring security I think.
I've excluded some urls so far like this:
<intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" />
Is it possible, to exclude a (Spring MVC)Controller, or is this the wrong way to approach this?
By the way, I also tried to annotate tho at the method:
#PreAuthorize("hasRole('IS_AUTHENTICATED_ANONYMOUSLY')")
Why don't you try permitAll instead?
<intercept-url pattern="/index.jsp" access="permitAll" />