Intercept url in spring security - java

I'm trying to understand how uel-interception works in spring security. Let assume that we write the following rule in our security config:
<security:intercept-url pattern="/secure/super/**" access="ROLE_WE_DONT_HAVE"/>
My question is is Spring Security going to create the object of AbstractSecurityInterceptor or what? I need to understand that because if my assumption about creation an object for each rule right I'm going to create the instances dynamically by myself in order to control authentication rule dynamically in runtime.

basically spring security will create one instance of FilterSecurityInterceptor
this filter will read the url pattern and will try to protected the mapped url
more information here spring security core

Related

Why and when use dynamic servlet registration?

I'm investigating a Spring Boot project generated by JHipster and found out that its request mappings aren't done via web.xml nor via Spring's #RequestMapping but like so:
ServletRegistration.Dynamic someServlet =
servletContext.addServlet("someServlet", new SomeServlet());
someServlet.addMapping("/someUrl");
someServlet.setAsyncSupported(true);
My questions are:
Are there any reasonable advantages of dynamic registration instead of classic mapping?
Is it spring-boot's standard of registering mappings or it's just a will of jhipster's owner?
Is someServlet.setAsyncSupported(true) just another way of making response.setHeader("Access-Control-Allow-Origin", "*")?
Is there any reasonable advantages of dynamic registration instead of classic mapping?
Dynamic servlet registration Servlet 3+ way of registering servlets. In Servlets 3 you can avoid creating web.xml and configure application in pure Java. It gives you some advantages like compile time check if everything is fine there and what's more important since you do it in Java code, you can do some additional checks or conditions - for example register particular servlet only if environment property is set or class is available on the classpath.
It's not a replacement for #RequestMapping. In case of Spring Boot you will use it most probably when you want to register some 3rd party servlet - like Dropwizard Metrics servlet in case of JHipster.
Is it spring-boot's standard of registering mappings or it's just a will of jhipster's owner?
There are at least 2 ways of registering additional servlets in Spring Boot. See answers here: How can I register a secondary servlet with Spring Boot?.
Your own controllers you map as usual with #RequestMapping.
Is someServlet.setAsyncSupported(true) just another way of making response.setHeader("Access-Control-Allow-Origin", "*")?
Nope. For setting this header you use usually CORSFilter (read more: Enabling Cross Origin Requests for a RESTful Web Service). asyncSupported flag is used to make servlet able to process request asynchronously.

Spring security #PreAuthorize("hasAnyRole('....')")

I am using spring security #PreAuthorise to check who and who cannot access methods in my service layer. It works really well. Usually my service methods are annotated with
#PreAuthorize("hasAnyRole('MY_USER_ROLE')")
My problem is that I have a war file made up of several jar files. Each of these jar files is responsible for a segment of business logic. I now want one of the services in one jar file to access another service in another jar file. This gets rejected because of the permissions. If I comment out the permission then everything works.
Is there anyway I can authenticate via spring before calling this service? (Perhaps with a dummy user?) Or perhaps turn off the security for jars within the same application? Or is my design wrong?
Anyone else has this sort of problem? What design should I use instead?
You need to give the thread that invokes the service (in the other jar) the permissions that are required by #PreAuthorize (for the invoked service).
If the thread is triggered in an web application by an user request, then this are normally the users permissions.
But if the thread is triggered by some timer service then you need to give them the right authentication
Authentication authentication = new UsernamePasswordAuthenticationToken("dummy", "password");
SecurityContext securityContext = SecurityContextHolder.getContext();
securityContext.setAuthentication(authentication);
I believe this is a good example where you should use Spring security #Secured annotation
What is #Secured annotation?
From version 2.0 onwards Spring Security has improved support substantially for adding security to your service layer methods. It
provides support for JSR-250 annotation security as well as the
framework's original #Secured annotation.
Source: Spring Security 3.1 Reference 2.4 Method Security
#Secured annotation allows you to put restrictions in your methods. For example, you can authorize a get() method to be accessible by all
registered users. But for the edit() method, you can mark it be
accessible by admins only.
Check out some tutorials at:
http://burtbeckwith.com/blog/?p=1398
http://krams915.blogspot.in/2010/12/spring-security-3-mvc-using-secured.html

How can do single login with spring security on two domains?

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

how to implement dynamic intercept url pattern i.e from database in spring security 3.0.5

I am new to spring security so not getting how to proceed for making the Url's to be authenticated should come from database.
What things to be added in applicationContext-security.xml and what custom java classes will be needed?
Please help me with example.
Thanks
I got the same issue with you. The following links would be helpful.
http://static.springsource.org/spring-security/site/faq.html#faq-dynamic-url-metadata
http://forum.springsource.org/showthread.php?112799-How-to-dynamically-decide-lt-intercept-url-gt-access-attribute-value-in-Spring-Security
How to dynamically decide <intercept-url> access attribute value in Spring Security?

Unable to retrieve security context from within Spring-Jersey

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 :)

Categories