We have a Spring web application which already uses Spring security for authenticating users and granting access to a group of restricted pages. However we have another group of resources that we wish to secure. For this second group we don't want user authentication but instead we want users to go a page: /access.html and enter an access code (previously emailed to them) and then they will be granted access to those resources without login. The access code (token) will only be valid for a limited period of time and then it expires.
Can I use spring security somehow to implement this in parallel to the user authentication setup we already have in place?
Sure, there are a couple of ways to do this. It sounds like all you need to do is create a filter that can check for your token in the session/request and create/update the Spring Security context to have the desired role. Then authorization proceeds as normal.
In particular you will be adding GrantedAuthories to your Authentication object for the Spring Security Context. There are a lot of details to this process and I admit my answer is not complete but a full answer would be pretty extensive.
I have done the similar things with cookie.
You can implement your own filter which extends GenericFilterBean
And then set the config with spring-security like below
<security:http ... >
....
<sec:custom-filter position="FORM_LOGIN_FILTER" ref="cookieAuthenticationFilter" />
</security:http>
Have a look at the source code of BasicAuthenticationFilter may be helpful.
Related
I have studied plenty tutorials and pages about Spring Boot Security. But none of them answered my questions. And here they are:
I´m building web app in Spring Boot. And I need to authenticate users via classic session (username, password). But as I know a lot of things are predefined in Spring Boot. And I want to change few things.
1) The only page which DO NOT NEED authentication is /. Here is also login form. Rest of pages MUST BE authenticated. So I do not want to use default URL /login. And what I have to write into form´s action?
2) I also need need unauthenticated routes for static resources. They are located: src/main/resource/static/css
3) Is there a way to edit logout? Like to add a code during logout action?
Can you show me how configure method of WebSecurityConfigurerAdapter should look like? I have already tried a lot of configurations, but they didnt work.
Thank you for your responses.
I recommend you to have a look at this tutorial for a specific login and logout page.
With antmatchers you can also define that your static content is not secured.See here
For adding logic between spring defined processes like logout you should have a look at the spring filter pipelines especially the Logoutfiler. This was already discussed here
It would also be an easy way to set the logout url to a rest endpoint, execute the action you want an then redirect to the auth service. In my opion the filter way is the better solution and cleaner.
I hope this helps to get on track. cheers
Is there a way to force my Java EE application to use j_security_check for authentication, but not authorization? I want to do authentication through a Standalone LDAP Repository, but I want to do programmatic authorization in my application.
Specifically, I do not want to do any configuration around Authorization (user role mapping to groups) within the Websphere Application Server admin console.
For example:
User logs in with 'user1' and password 'password1' which are correct
Websphere finds this person in LDAP, knows they are who they say they are (Authentication)
I check from a file on the file system if this user is authorized or not (Authorization)
I suggest using Spring Security for this. We have implemented this exact pattern in WebSphere. The trick is to use the pre-authentication mechanism that Spring Security provides and then define only the authorization rules in the configuration.
<http>
<session-management session-fixation-protection="none"/>
<custom-filter position="PRE_AUTH_FILTER" ref="preAuthenticationFilter"/>
<intercept-url pattern="/j_security_check" filters="none"/>
<intercept-url pattern="/ibm_security_logout" filters="none"/>
<!-- put authorization intercept-url elements here... -->
</http>
You have to define some other beans as well, such as the pre-authenticated filter and a custom entry point, but that's documented here: http://static.springsource.org/spring-security/site/docs/3.0.x/reference/preauth.html
Have a look at Spring Security. The concepts of authentication and authorisation are split.
Authentication is handled by an AuthenticationProvider (an LdapAuthenticationProvider implementation is part of spring). The authentication provider delegates to fetch details of the user, which includes a list of GrantedAuthority objects which can represent a user's permissions.
LdapAuthenticationProvider by default attempts to get granted authorities from the directory, so you will need to provider your own LdapAuthoritiesPopulator implementation which loads from the file system.
Java EE Security can be split as well. It depends on your container's implementation however.
Since you mention websphere this document might be of interest.
I have web application and two domains for it - example.com and example.ru
example.com - for international
example.ru - for local country
My web app using spring security for authorization users but if user login through example.com on example.ru he isn't logged.
How can do that if user login through example.com or example.ru he will be logged on both domains?
PS: BTW my web application use authorization through OpenID and OAuth
As mentioned you need a single sign on solution, Cloudseal provides a spring security extension which includes a spring namespace so you just need to do something like:
<security:http entry-point-ref="cloudseal">
<security:intercept-url pattern="/protected/user.do" access="IS_AUTHENTICATED_FULLY" />
<security:intercept-url pattern="/protected/admin.do" access="ROLE_ADMIN" />
</security:http>
<cloudseal:sso endpoint="http://cloudseal.com" entry-point-id="cloudseal" app-id="quickstart">
<cloudseal:keystore location="WEB-INF/keystore.jks" password="nalle123">
<cloudseal:key name="apollo" password="nalle123" />
</cloudseal:keystore>
<cloudseal:metadata location="WEB-INF/idp.xml" />
</cloudseal:sso>
See www.cloudseal.com/platform/spring-security-single-sign-on
While this type of functionality is by no means trivial to achieve, it is in fact possible without modifying Spring.
The actual code is too large to post, so I'll try to outline the basic principle and leave the coding to you.
Extend Spring's SavedRequestAwareAuthenticationSuccessHandler
and implement functionality to serialize and write the
Authentication object to a Session cookie with a global scope. See
documentation for the authentication-success-handler-ref attribute
in Spring's <sec:http> tag for more information on how to wire
this up. (Note: If the problem were sso across multiple web apps on
the same domain, you could of course limit the cookie scope to the
current domain).
In all your web apps, add to web.xml a <filter> definition
named springSecurityFilterChain and class
org.springframework.web.filter.DelegatingFilterProxy and a
<filter-mapping> for the filter with a URL pattern of /* You don't have to create the actual bean, Spring Security provides a default implementation for you.
In all your web apps, add to web.xml a <filter> definition
named singleSignonAuthenticationFilterChain with class
org.springframework.web.filter.DelegatingFilterProxy and a
corresponding <filter-mapping> for the filter with a URL pattern
of /*
Now you add a new bean called
singleSignonAuthenticationFilterChain, which should point to a
class that implements Filter. In the doFilter() method, check if
there is a session attribute called SPRING_SECURITY_CONTEXT. If
there is, then we are already logged in. Otherwise, take the
serialized Authentication token, deserialize it and use
SecurityContextHolder.getContext().setAuthentication(authentication)
to authenticate the user with Spring. Also remember to
session.setAttribute("SPRING_SECURITY_CONTEXT",
SecurityContextHolder.getContext()) or the authentication will take
place each time, which is unnecessary.
A twist to (4) is that if you find out that there is no attribute called SPRING_SECURITY_CONTEXT, then it could be because the user has just logged out from the current web application. In this case he must be logged out globally, so you want to remove the cookie containing the serialized authentication token in this case.
It's kind of complex to write up in a one page summary, but I hope you get the general idea. We currently have this implemented in a complex application consisting of multiple web applications, and it works nicely.
It's impossible without modifying spring security code. I did it sometimes ago but is very hard to maintenance
Cas is the easeiest way to this in java world.
http://www.jasig.org/cas
In my web application, there are times when an authenticated admin might want to impersonate another valid user of a system without having to know that user's password.
How can I use Spring Security to give admin users the ability to impersonate normal (non-admin) users of the system?
The Spring Security documentation is silent on this and I can't find anything anywhere. Surely someone must have solved this.
Thanks!
It's in the Spring Security 3 and Spring Security 4 docs aptly named, "Run-As Authentication Replacement."
The AbstractSecurityInterceptor is able to temporarily replace the Authentication object in the SecurityContext and SecurityContextHolder during the secure object callback phase.
I believe the recommended way to do this in Spring Security is with the Domain Access Control lists, see GrantedAuthoritySid #
http://static.springsource.org/spring-security/site/docs/3.1.x/reference/domain-acls.html
However, impersonating another user is more than just having a "delegate identity", you should also consider the implications on logging:
Do you want your logging to appear as Original User or Impersonated User (or both?)
Do you want the "impersonation" to show only what the impersonated user sees, or the superset of permissions of the Original User and Impersonated User?
Yet another possibility is to create a "log in as" feature, which essentially changes the principal identity of the current session - or starts a new session with the impersonated identity.
In all of the above, you may inadvertantly open up a security issue - so I think this is why impersonate-style features are not that common place. Rather, designs trend towards Role Based Access Control (RBAC) or Attribute Based Access Control (ABAC). Using RBAC / ABAC, you could create a delegate style feature where you create delegate attributes/roles - and in the special cases where you need to show the source/target of the delegation (e.g. for audit logs), you handle those as corner cases.
If you want an admin user to be able to impersonate another user (eg for QA/Testing purposes), have a look at the SwitchUserFilter
A decent example of the XML config you need is provided here
I am trying to retrieve a security context within my spring-jersey bean, however I keep getting Null authentication. When I run the same command from within my spring application it correctly retrieves the current logged in users security context.
The configuration of spring-jersey requires creating a separate servlet to the main spring application, thus the web.xml has two servlet's - one for spring app, second for jersey rest api.
Assuming the problem is related to this, I tried setting the security context sharing mode to global, however I still unable to get the context information from within Jersey.
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL)
Any help with this would be greatly appreciated!
Many thanks,
Nigel
Perhaps user is simply not authenticated, because your Jersey requests don't have a session cookie and therefore are not associated with the authenticated user's session?
You may check it by enabling anonymous authentication in Spring Security - you should get anonymous authentication instead of null if the guess is right.
#axtavt Thank you for the comment. This clue helped solve my problem, checking how my security filters were configured, I found this line in my spring security configuration
<security:intercept-url pattern="/api/**" filters="none" />
This line effectively disables all spring security filters, removing this fixed the problem.
Many thanks for your help :)