Can anybody explain me how Spring Security works? The architecture and the main classes or interfaces, I want to have overview about this framework. How Spring security work from the authentication to access control, which classes or interfaces in each stage??? I saw in spring has some annotation like #Secured, how Spring process them and where Spring collects information to do security check?
Well first you should know that exists a spring security filter chain (describe later on here).
When the context is loaded the Authentication Manager populates the Security Context, and this context has all the information about the security policies to use, and how to use them.
When a request is received the flow is:
1) The security interceptor capture it to protect secured resources
2) Asks the Access Decision Manager what to do
3) Then this manager checks if the access should be granted or not (based on a voters principle (based on rules))
4) if so the filter calls the proceed method
5) if not a security exception is thrown
The spring security filter chain is:
1) SecurityContextPersistenceFilter
- if has session access is granted and request goes on
- if not it goes to 2)
2) Logout filter (do nothing if is not a logout request and proceed)
3) UsernameAndPasswordAuthenticationFilter
- extracts the username and the password from request params and passes it to the authenticationManager.authenticate(username, password)
4) The AuthenticationManager performs the authentication based on it policy (ex: Basic, Digest, RSA)
- If authenticated add information to response headers about session id to be remembered by SecurityContextPersistenceFilter as session
- If not a spring security exception is thrown
5) Proceed to ExceptionTranslationFilter if no exception thrown so far do nothing, on the request side does nothing, only performs when responding, the request is then passed to FilterSecurityInterceptor if the resource has no attributes does nothing (base configs)
6) Finally it accesses the secured resource and returns with the exact inverted order
I recomend you to open and check this classes one by one, break points in it, debug them, look ate the stack calls. This way you will understand the security flow.
Plus I encourage you to refer to the documentation if any doubt persists.
Hope I this helps you or someone else.
Cheers
I think that this is too broad for a SO question. I suggest that you read the Spring Security Manual (especially Chapters 5 and 7 which give a good overview of how it all fits together), and come back if you have more specific questions. (And ask them one at a time ...)
Related
I have an AuthenticationServerInterceptor for grpc-java, that authenticates any request. However, the request processing itself is split into multiple threads.
For the sake of simplicity lets assume, that there are 3 parts (that are potentially executed by different threads):
Establishing the request and doing the authentication
[1..* times] Processing the parts of the request
Closing the request
What should I pass to the other places in order to allow me to restore the authenticated context in the later cases? (All three parts belong to a single request and they share a grpc-context)
The Authentication instance
The SecurityContext instance
If I pass along the Authentication instance, then I ensure that for each part of the request the original authentication is restored. However, any additional information that might be stored in the (custom) security context will be lost.
If I pass along the SecurityContext instance, then I ensure that for each part of the request the additional information and an authentication are passed along, but the developer must be careful with modifying that context.
Unfortunately I couldn't find any information about which to pass along in the docs.
I cannot just decide on either of those, because the authentication process is part of a library and it doesn't know anything about whether there might be additional details in the context and what the developer might do when processing the request parts.
Here is my current implementation, that is tested to be working+thread safe:
https://github.com/yidongnan/grpc-spring-boot-starter/blob/2ee90f16ee4295370ee47c40829805ff1a9f4f51/grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/security/interceptors/DefaultAuthenticatingServerInterceptor.java#L59
TLDR: Is spring-security's SecurityContext more thread-scoped or more request-scoped?
The problem is that the default option in Spring Security is thread Local, meaning that if your request create new threads, these new ones will be created with an empty Security context. You can set it to mode Inheritable Thread Local with the following code:
#Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
methodInvokingFactoryBean.setArguments(new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
return methodInvokingFactoryBean;
}
I have a J2EE REST-based app using Spring Security 4.0.1.RELEASE. Needless to say, Spring documentation on sessionCreationPolicy and sessionFixation is sparse, aside from targeted questions here on StackOverflow.
I'm using a Java-based config for Spring Security like this:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(secureEnabled=true, prePostEnabled=true, jsr250Enabled=true, order=1)
public class DefaultSecurityBeansConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.sessionFixation().migrateSession()
.and()...; // additional config omitted for brevity
}
}
I'd really just like to know what behavior to expect from Spring, as it relates to JSESSIONID, given all possible combinations of sessionCreationPolicy and sessionFixation.
Possible values in the SessionCreationPolicy enum are ALWAYS, NEVER, IF_REQUIRED, and STATELESS.
Possible values for session fixation are newSession, migrateSession, changeSessionId, and none.
Thank you.
NOTE: What prompted this question is that I am not seeing a new JSESSIONID on every request when I have sessionCreationPolicy set to IF_REQUIRED and sessionFixation set to changeSessionId. A JSESSIONID is correctly created, but is maintained across requests thereafter. I generalized my question about all combinations to hopefully help others in a similar situation with slightly different settings.
It's important to keep in mind that Spring Security doesn't always have full control of the HttpSession. It can create one itself, but it can also be provided a Session object by the container.
For SessionCreationPolicy.IF_REQUIRED, the docs state:
Spring Security will only create an HttpSession if required
In your particular case, you're not seeing a new JSESSIONID for every request for at least 2 possible reasons:
With your current configuration, Spring has the option of creating a Session if it needs one.
SessionCreationPolicy.IF_REQUIRED also appears to allow Spring Security to use the Session it is provided with. Your container might be providing this object if this is the case, and so the session is maintained across multiple requests (as is expected if you're in a session).
If you wanto to disable #1, use SessionCreationPolicy.NEVER:
Spring Security will never create an HttpSession, but will use the HttpSession if it already exists
The only SessionCreationPolicy that will ensure that Spring Security uses NO SESSIONS is SessionCreationPolicy.STATELESS.
As regards SessionFixation, it only comes into play when you have multiple sessions for one user, after authentication. At this point, the SessionCreationPolicy is somewhat irrelevant.
SessionCreationPolicy: used to decide when (if ever) to create a new session
SessionFixation: once you have a session for a user, what to do with the session if the user logs in again
Hope this helps!
I am very much new to web services. I have exposed some REST services using Jersey 2 in integration with Spring. Now I need to secure those rest services using authentication with username/password. I am told not to use Spring Security.
I have no idea of how to do this. I did search on the net but various links show various implementation and I am unable to decide how to proceed with it.
A common way for authenticating with username and password is to use Basic Authentication. Basically the client needs to send a request header Authorization, with the the header value as Basic Base64Encoded(username:password). So is my username is peeskillet and my password is pass, I, as a client, should set the header as
Authorization: Basic cGVlc2tpbGxldDpwYXNz
In a servlet environment, the container should have support for Basic authentication. You would configure this support on the web.xml. You can see an example in 48.2 Securing Web Applications of the Java EE tutorial. You will also notice in an example
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
That is for SSL support. This is recommended for Basic Authentication.
If you don't want to deal with the hassle of working with security domains and login modules, realm, and such, that would be required to customize the servlet support, or if you're just not in a servlet environment, implementing Basic Auth in a ContainerRequestFilter is really not too difficult.
You can see a complete example of how this could be done at jersey/examples/https-clientserver-grizzly. You should focus on the SecurityFilter
The basic flow in the filter goes something like this
Get the Authorization header. If it doesn't exist, throw an AuthenticationException. In which case the AuthenticationExceptionMapper will send out the header "WWW-Authenticate", "Basic realm=\"" + e.getRealm() + "\", which is part of the Basic Auth protocol
Once we have the header, we parse it just to get the Base64 encoded username:password. Then we decode it, then split it, then separate the user name and password. If any of this process fails, again throw the WebApplicationException that maps to a 400 Bad Request.
Check the username and password. The example source code just checks if the username is user and the password is password, but you will want to use some service in the filter to verify this information. If either of these fail, throw an AuthenticationException
If all goes well, a User is created from the authenticate method, and is injected into an Authorizer (which is a SecurityContext). In JAX-RS, the SecurityContext is normally used for authorization`.
For the authorization, if you want to secure certain areas for certain resources, you can use the #RolesAllowed annotation for your classes or methods. Jersey has support for this annotation, by registering the RolesAllowedDynamicFeature.
What happens under the hood is that the SecurityContext will be obtained from the request. With the example I linked to, you can see the Authorizer, it has an overridden method isUserInRole. This method will be called to check against the value(s) in #RolesAllowed({"ADMIN"}). So when you create the SecurityContext, you should make sure to include on the overridden method, the roles of the user.
For testing, you can simply use a browser. If everything is set up correctly, when you try and access the resource, you should see (in Firefox) a dialog as seen in this post. If you use cURL, you could do
C:/>curl -v -u username:password http://localhost:8080/blah/resource
This will send out a Basic Authenticated request. Because of the -v switch, you should see all the headers involved. If you just want to test with the client API, you can see here how to set it up. In any of the three cases mentioned, the Base64 encoding will be done for you, so you don't have to worry about it.
As for the SSL, you should look into the documentation of your container for information about how to set it up.
So this is really a matter what you would like to achieve. My case was to get this thing running with mobile and a One-Page-App JavaScript.
Basically all you need to do is generate some kind of header that value that will be needed in every consecutive request you client will make.
So you do a endpoint in which you wait for a post with user/password:
#Path("/login")
public class AuthenticationResource {
#POST
#Consumes("application/json")
public Response authenticate(Credentials credential) {
boolean canBeLoggedIn = (...check in your DB or anywher you need to)
if (canBeLoggedIn) {
UUID uuid = UUID.randomUUID();
Token token = new Token();
token.setToken(uuid.toString());
//save your token with associated with user
(...)
return Response.ok(token).type(MediaType.APPLICATION_JSON_TYPE).build();
} else {
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}
}
Now you need to secure resource with need for that token:
#Path("/payment")
#AuthorizedWithToken
public class Payments {
#GET
#Produces("application/json")
public Response sync() {
(...)
}
}
Notice the #AuthorizedWithToken annotation. This annotaation you can create on your own using special meta annotation #NameBinding
#NameBinding
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface AuthorizedWithToken {}
And now for the filter that implements checking of the header:
#AuthorizedWithToken
#Provider
public class XAuthTokenFilter implements ContainerRequestFilter {
private static String X_Auth_Token = "X-Auth-Token";
#Override
public void filter(ContainerRequestContext crc) throws IOException {
String headerValue = crc.getHeaderString(X_Auth_Token);
if (headerValue == null) {
crc.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Missing " + X_Auth_Token + " value").build());
return;
}
if(! TOKEN_FOUND_IN_DB) {
crc.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Wrong " + X_Auth_Token + " value").build());
return;
}
}
}
You can create any number of your own annotations checking for various things in the http request and mix them. However you need to pay attention to Priorities but that actually easy thing to find. This method needs using https but that is obvious.
Security comes in two main flavours :
Container Based
application based
the standard way to secure spring applications is to use Spring Security (formerly Acegi).
It would be interesting to know why you're not being allowed to use that.
You could use container based security, but I'm guessing that your use of spring precludes that option too.
Since the choice of Spring is usually to obviate the need for the use of a full J2EE container (Edit : though as pointed out below by others, most ordinary servlet containers do allow you to implement various container based security methods)
This really only leaves you with one option which is to roll your own security.
Your use of Jersey suggests that this might be a REST application.
In which case you really ought to stick with standard HTTP Authentication methods that
comes in the following flavours in reverse order of strength :
BASIC
Digest
Form
Certificate
REST applications are usually supposed to be 'stateless', which essentially rules out form based authentication (because you'd require the use of Session)
leaving you with BASIC, Digest and Certificate.
Your next question is, who am I authenticating. If you can expect to know the username AND the password of the user based on what URL they requested (say if it's one set of credentials for all users) then Digest is the best bet since the password is never sent, only a hash.
If you cannot know the Password (because you ask a third party system to validate it etc.) then you are stuck with BASIC.
But you can enhance the security of BASIC by using SSL, or better yet, combining BASIC with client certificate authentication.
In fact BASIC authentication over HTTPS is the standard technique for securing most REST applications.
You can easily implement a Servlet Filter that looks for the Authentication Header and validates the credentials yourself.
There are many examples of such filters, it's a single self contained class file.
If no credentials are found the filter returns 401 passing a prompt for basic auth in the response headers.
If the credentials are invalid you return 403.
App security is almost an entire career in itself, but I hope this helps.
As the former posts say, you could go with different options, with a varying overhead for implementation. From a practical view, if you're going to start with this and are looking for a comfortable way for a simple implementation, I'd recommend container-based option using BASIC authentication.
If you use tomcat, you can setup a realm, which is relatively simple to implement. You could use JDBCRealm, which gets you a user and password from specified columns in your database, and configure it via server.xml and web.xml.
This will prompt you for credentials automatically, everytime you are trying to access your application. You don't have any application-side implementation to do for that.
What I can tell you now is that you already did most of the 'dirty' job integrating Jersey with Spring. I recommend to you to go an Application-based solution, is it does not tie you to a particular container. Spring Security can be intimidating at first, but then when you tame the beast, you see it was actually a friendly puppy.
The fact is that Spring Security is hugely customizable, just by implementing their interfaces. And there is a lot of documentation and support. Plus, you already have a Spring based application.
As all you seek is guidance, I can provide you with some tutorials. You can take advantage from this blog.
http://www.baeldung.com/rest-with-spring-series/
http://www.baeldung.com/2011/10/31/securing-a-restful-web-service-with-spring-security-3-1-part-3/
I working on Spring MVC app. The app funcionality is accessible through ReST API which jsp containing ajax logic consume. I am using spring security with defined roles (USER, COMPANY, ADMIN). Methods use requestMapping with responseBody such as:
www.app.com/auth/{userId}/request/{requestId}
It, of course, support GET for obtaining resource and POST for its creating or updating.
The problem is that after succesful login with, for example, userId = 1 I want GET request with requestId = 99. But when I run WebDev client for Chrome, I can also access another resource with easy request in format
www.app.com/auth/5/request/{requestId}
So basically, I can access resources, which I am not allowed to see. I hope you got the idea, where I am heading.
My question is - What is the best approach to secure this?
I was thinking about storing logged user Id (Integer) in session and comparing it everytime request for resource is made, but it seems to me that I am pulling the wrong end of rope :)
Thank you for any advice
You should have a look into the Expression-Based Access Control section of the spring security documentation.
Example copied from the documentation:
#PreAuthorize("#contact.name == authentication.name")
public void doSomething(Contact contact) {
..
}
This would check if name of the contact is equal to the name of the currently logged in user.
Using this this feature you can build much more sophisticated access rules than you could do with simple roles. However, this does not exclude using roles. You can still keep roles for basic security checks.
I'm implementing an OAuth 2.0 provider for my company's REST API using spring security oauth.
For some reason when using the Token endpoint spring security oauth mandates the client to send their desired scope as a request parameter (this happens in the ClientCredentialsChecker.validateScope method).
As I understand the spec section about Access Token Scope the scope parameter is optional BUT a provider can decide it fails an authorization request if no scope exists.
My questions are:
Do I understand correctly the spec as allowing a provider to mandate
the scope?
Does anyone know why spring security oauth chose to implement the stricter interpretation of the spec without allowing this to be configured?
Thanks
I think the question here really comes down to the concept of scope binding. You're right that the specification states that the scope parameter is optional, but whether the scope has to be defined in a service implementing OAuth 2 is really up to the implementer (in this case Spring).
Now to the concept of scope binding. When implementing scopes, or the information that you want to be able to access from a user, you have two basic types - bound and unbound scopes. When using bound scopes, the scopes will need to be defined when you create your application and get your OAuth key and secret. If implementing unbound scopes (like Spring), the scopes need to be defined during the first redirect call to have the user auth. In many cases when no scopes are defined, a service implementing unbound scopes will use a default set of user details that you can access. It appears that in the Spring case the scope is required.
Disclaimer: I have not worked with the Spring security OAuth implementation before.
Just to give you some visuals on the difference between bound and unbound, here are some examples:
Facebook uses unbound scopes to request user data, so their initial redirect request can look like this:
//construct Facebook auth URI
$auth_url = sprintf("%s?redirect_uri=%s&client_id=%s&scope=email,publish_stream",
$authorization_endpoint,
$callback_url,
$key);
In the case of Gowalla (back when Gowalla was still available), they used scopes that were bound to the OAuth key, so when you made that initial request the scope didn't need to be defined, giving you a request that looked more like this (notice the missing scope param):
//construct Gowalla auth URI
$auth_url = sprintf("%s?redirect_uri=%s&client_id=%s",
$authorization_endpoint,
$callback_url,
$key);
I hope that helps,
Jon