Spring Security oddity in <intercept-url> when specifying method - java

I've been playing around with Spring Security a bit and noticed the following oddity.
When I specify the <http> block like this in my security context XML.
<http>
<http-basic/>
<port-mappings>
<port-mapping http="8080" https="8181"/>
</port-mappings>
<intercept-url pattern="/url1**" access="ROLE_ROLE1" requires-channel="https"/>
<intercept-url pattern="/url2**" access="ROLE_ROLE2"/>
<intercept-url pattern="/url3**" access="ROLE_ROLE3" />
<!-- <intercept-url pattern="/**" access="ROLE_ADMIN" />
</http>
All the urls seem to trigger a HTTP basic authentication pop up when I hit the various URLs with the browser.
This is good and what I expected, but when I add a method parameter to 1 of the intercept URLs like this:
<http>
<http-basic/>
<port-mappings>
<port-mapping http="8080" https="8181"/>
</port-mappings>
<intercept-url pattern="/url1**" access="ROLE_ROLE1" requires-channel="https"/>
<intercept-url pattern="/url2**" access="ROLE_ROLE2" method="GET"/>
<intercept-url pattern="/url3**" access="ROLE_ROLE3" />
<!-- <intercept-url pattern="/**" access="ROLE_ADMIN" />
</http>
The basic authentication is turned off for all the URLs except the one I've explicitly set the method on (/url2).
Is this how it's supposed to work, because it seems a little goofy to me. Is this a bug?

Now I have tested url1 with https and it works. I got redirected and then the login dialog showed up.
Setting logging level to DEBUG it prints:
DEBUG DefaultFilterInvocationDefinitionSource,http-8443-1:196 - Converted URL to lowercase, from: '/url1/'; to: '/url1/'
DEBUG DefaultFilterInvocationDefinitionSource,http-8443-1:224 - Candidate is: '/url1/'; pattern is /url2**; matched=false
DEBUG DefaultFilterInvocationDefinitionSource,http-8443-1:224 - Candidate is: '/url1/'; pattern is /url1**; matched=true
DEBUG AbstractSecurityInterceptor,http-8443-1:250 - Secure object: FilterInvocation: URL: /url1/; ConfigAttributes: [ROLE_USER]
DEBUG XmlWebApplicationContext,http-8443-1:244 - Publishing event in context [org.springframework.web.context.support.XmlWebApplicationContext#17af46e]: org.springframework.security.event.authorization.AuthenticationCredentialsNotFoundEvent[source=FilterInvocation: URL: /url1/]
DEBUG ExceptionTranslationFilter,http-8443-1:150 - Authentication exception occurred; redirecting to authentication entry point
This is the configuration:
<http>
<http-basic/>
<port-mappings>
<port-mapping http="8080" https="8443"/>
</port-mappings>
<intercept-url pattern="/url1**" access="ROLE_USER" requires-channel="https"/>
<intercept-url pattern="/url2**" access="ROLE_TELLER" method="GET"/>
<intercept-url pattern="/url3**" access="ROLE_SUPERVISOR" />
</http>

Related

Spring Security authentication for a REST API

At the moment a basic REST API has 3 URL's (not actual URL's)
http://localhost:8080/app
http://localhost:8080/app/home
http://localhost:8080/app/product
Currently all three URL's have basic authentication using Spring Security using XML.
However, I would like to remove the basic authentication for URL 1.
I have unsuccessfully tried the following the following approaches (reduced XML)
<http>
<intercept-url pattern="/app/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
<http-basic/>
</http>
vs
<http>
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
<intercept-url pattern="/app/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<http-basic/>
</http>
Is there something I'm missing in my configuration or there is another way to achieve this using Spring Security?
If you set the context path of your server to 'app' so all the paths in your application will be localhost:8080/app/**.
If you want to allow everyone to access all the paths in the application and only for authenticated users to access /home and /product you should do this:
<http>
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/home" access="IS_AUTHENTICATED_FULLY" />
<intercept-url pattern="/product" access="IS_AUTHENTICATED_FULLY" />
<http-basic/>
</http>
This way everyone will get to localhost:8080/app but only IS_AUTHENTICATED_FULLY users will access to /home & /product.
Shouldn't you be doing something like this:
<http>
<intercept-url pattern="/app/**" access="IS_AUTHENTICATED_FULLY"/>
<intercept-url pattern="/app/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<http-basic/>
</http>

getPrincipal() method returns anonymous user

I'm trying to get the connected user via spring security method
public static User getConnectedUser() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User currentUser=auth.getPrincipal();
}
When i invoke this method from a webservice get method using postman it returns anonymousUser even if am logged in.
Here is my spring security configuration:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/app/admin/**" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/app/passwordHint*" access="hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_ANONYMOUS')"/>
<intercept-url pattern="/app/requestRecoveryToken*" access="hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_ANONYMOUS')" />
<intercept-url pattern="/app/updatePassword*" access="hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_ANONYMOUS')" />
<intercept-url pattern="/app/signup*" access="hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_ANONYMOUS')"/>
<intercept-url pattern="/app/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>
<form-login login-page="/login" authentication-failure-url="/login?error=true" login-processing-url="/j_security_check"/>
<remember-me user-service-ref="userDao" key="e37f4b31-0c45-11dd-bd0b-0800200c9a66"/>
<custom-filter ref="ajaxTimeoutRedirectFilter" after="EXCEPTION_TRANSLATION_FILTER"/>
</http>
Even when i added this line <intercept-url pattern="/*" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/> to the above configuration it returns the anonymousUser.
Here is the url i request from postman.
http://localhost:8080/myApp/services/api/seal/
Yor intercept-url are all not match because your path begins with services not with app.
If your context root is myApp, your configuration should be:
<intercept-url pattern="/services/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>

How can I allow GET requests without authentication but secure other HTTP methods?

I've created a webservice with spring roo and added spring security to the project. Everything works fine so far but now I want to allow to access entities information via HTTP GET requests without any authentication. The other HTTP methods like POST, PUT etc. should stay secure.
My applicationContext-security.xml looks like the following but when I do a HTTP GET on "/releaseupdates/" with a "Accept: application/json" header it always returns the login page (I think spring security redirects to the login page internally):
<http auto-config="true" use-expressions="true">
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" />
<logout logout-url="/resources/j_spring_security_logout" />
<!-- Configure these elements to secure URIs in your application -->
<intercept-url pattern="/releaseupdates/**" access="permitAll" method="GET" />
<intercept-url pattern="/releaseupdates/**" access="hasRole('ROLE_ADMIN')" method="POST" />
<intercept-url pattern="/releaseupdatestatuses/**" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/choices/**" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/member/**" access="isAuthenticated()" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/login/**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
There is also an annotation #PreAuthorize which could be your friend here. The annotation could be at class or method level on your Controllers.
Here's an example:
#Controller
#RequestMapping("/releaseupdates")
public class ReleaseUpdateController {
#RequestMapping(method=RequestMethod.GET)
public String unprotectedGetRequest() {
//do something, no protection
}
#PreAuthorize("hasRole('ROLE_ADMIN')")
#RequestMapping(method=RequestMethod.POST)
public String securePostRequest() {
//do something, secured
}
}

Using Spring Security 3.1 to secure the same RESTful resources with both form-login and http-basic security

I have a java web application running on Tomcat 7.
I am using Spring 3.2 with Spring Security 3.1 on the backend, and am exposing an API via RESTful URLs following the /api/** pattern.
The UI for the web application is built using BackboneJS. I am using Backbone models mapped directly to the RESTful URLS.
The UI is locked down using form-login authentication, so the user is always redirected to the login screen if they have are not currently authenticated.
I am now attempting to expose the same RESTful URLs to another external service using http-basic authentication. Unfortunately, when securing the same URL pattern, it seems Spring will not allow me to use more than one filter chain. Whichever is defined first in the configuration file seems to take precedence.
I would hate to have to map to separate URL patterns for the same RESTful resources, but it seems like I may not have a choice.
Here is the important sample of my (currently broken) spring security configuration:
<!-- configure basic http authentication -->
<http pattern="/api/**" create-session="stateless">
<intercept-url pattern="/**" access="ROLE_USER"/>
<http-basic/>
</http>
<!-- configure form-login authentication -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/ui/login" access="permitAll" />
<intercept-url pattern="/ui/logout" access="permitAll" />
<intercept-url pattern="/ui/loginfailed" access="permitAll" />
<intercept-url pattern="/**" access="ROLE_USER" />
<custom-filter ref="ajaxTimeoutRedirectFilter" after="EXCEPTION_TRANSLATION_FILTER" />
<form-login login-page="/ui/login" default-target-url="/" authentication-failure-url="/ui/loginfailed" />
<logout logout-success-url="/ui/logout" />
<session-management invalid-session-url="/ui/login"/>
</http>
My question is:
Is it possible to configure two different types of security (http-basic and form-login) for the same URL patterns using Spring Security? Is there a best practice for this type of scenario?
Thank you.
Why don't you just merge the two <http> elements like this:
<http pattern="/api/**" use-expressions="true">
<intercept-url pattern="/ui/login" access="permitAll" />
<intercept-url pattern="/ui/logout" access="permitAll" />
<intercept-url pattern="/ui/loginfailed" access="permitAll" />
<intercept-url pattern="/**" access="ROLE_USER" />
<http-basic/>
<custom-filter ref="ajaxTimeoutRedirectFilter" after="EXCEPTION_TRANSLATION_FILTER" />
<form-login login-page="/ui/login" default-target-url="/" authentication-failure-url="/ui/loginfailed" />
<logout logout-success-url="/ui/logout" />
<session-management invalid-session-url="/ui/login"/>
</http>
This would set up both a UsernamePasswordAuthenticationFilter and a BasicAuthenticationFilter in the same filter chain which could serve the ui client, and the external service as well.
Not possible out of the box to apply 2 different filter chain for a single URL pattern.
But it is a advisable to have unique URL patterns as UI and API, as you would have to apply a completely different filter chain in future.
For example the SecurityContextRepository hold the session information and is retrieved for each request. You don't want to apply the same for UI and API access through basic auth
Try to replace pattern="/" by pattern="/api/" in API config:
<http pattern="/api/**" create-session="stateless">
<intercept-url pattern="/api/**" access="ROLE_USER"/>
<http-basic/>
</http>

https in default-target-url spring security

we are using spring security into our systems and our server is using the https scheme.
However the application is running on http not https, so the server, being apache,
is the https handler. whereas the application is running on http behind a firewall.
Working code:
<form-login login-page="/Login.html"
authentication-failure-url="https://www.ourapp.com/FailureLogin.jsp"
always-use-default-target="false"
default-target-url="https://www.ourapp.com/SuccessLogin.jsp"/>
<form-login login-page="/Login.html"
authentication-failure-url="https://www.ourapp.com/FailureLogin.jsp"
always-use-default-target="false"
default-target-url="https://www.ourapp.com/SuccessLogin.jsp"/>
Not working code:
<form-login login-page="/Login.html"
authentication-failure-url="/FailureLogin.jsp"
always-use-default-target="false"
default-target-url="/SuccessLogin.jsp"/>
<form-login login-page="/Login.html"
authentication-failure-url="/FailureLogin.jsp"
always-use-default-target="false"
default-target-url="/SuccessLogin.jsp"/>
is there any way to mention :
Redirect to Url ending with /SuccessLogin.jsp but using https protocol ?
For reference, question is cross posted # Code ranch
PS: I can TargetUrlResolver help me in configurations ?
use requires-channel="https"
<http>
<intercept-url pattern="/**" requires-channel="https" />
</http>
If non standard ports in use provide port-mappings
<http>
<intercept-url pattern="/**" requires-channel="https" />
<port-mappings>
<port-mapping http="80" https="443" />
<port-mapping http="9080" https="9443" />
<port-mappings>
</http>

Categories

Resources