spring-security: where did the Principal go? - spring-security

I've been playing with spring-security for a while and for some reason I'm not able to access the principal in the JSPs even when authentication and authorization are working right.
This is my index.jsp:
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<%# page import="org.springframework.security.core.context.SecurityContextHolder" %>
for authenticated<br/>
for admins
<sec:authorize access="! isAuthenticated()">
not logged in
</sec:authorize>
<sec:authorize access=" isAuthenticated()">
logged in
</sec:authorize>
Your principal object is....: <sec:authentication property="principal.username" /><br/>
Authentication = <%=SecurityContextHolder.getContext().getAuthentication() %>
<p>Logout</p>
And this is the *-security-xml:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http pattern="/loggedout.jsp" security="none"/>
<http pattern="/index.jsp" security="none"/>
<http pattern="/login.jsp" security="none"/>
<http auto-config="true">
<intercept-url pattern="/admin/*" access="ROLE_ADMIN,ROLE_SUPERUSER" />
<intercept-url pattern="/forAuthenticated.jsp" access="ROLE_USER" />
<intercept-url pattern="/logoutSuccess*" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page="/login.jsp"
authentication-failure-url = "/login.jsp?login_error=1"/>
<logout logout-success-url="/loggedout.jsp" delete-cookies="JSESSIONID"/>
<session-management invalid-session-url="/sessionTimeout.htm" />
</http>
<global-method-security pre-post-annotations="enabled"/>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service id="userDetailsService">
<user name="username" password="password" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="test" password="test" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
When I try to access the forAuthenticated.jsp I'm prompted for login. After entering test/test I access the forAuthenticated page, but not the admin/adminUsers.jsp. This is ok, but the problem is that I can't access the principal in the index.jsp. This is what index.jsp prints when logged in as test/test. Note that I can't see the not logged in nor logged in traces:
for authenticated
for admins
Your principal object is....:
null
Logout
What am I missing? what should I double-ckeck()?

As Karthikeyan suggests in his comment, the problem is the following line:
<http pattern="/index.jsp" security="none"/>
which effectively causes requests matching the given pattern to be dispatched straight to the handler method skipping the Spring Security filter chain. Not even the SecurityContext gets initialized in this case, so the authentication object won't be available for the <sec:authorize> tag based on which it should make decision whether to reveal the wrapped content (and it obviously won't by default).
The reference doc states it clearly as well:
A request pattern can be mapped to an empty filter chain, by setting this attribute (security) to none. No security will be applied and none of Spring Security's features will be available.
Instead of mapping an empty filter chain, you should simply allow anonymous access:
<sec:intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>

Related

Configuring remember-me in spring security

How can i configure remember-me service in spring security.Am using spring3.0 +hibernate3+ struts2.I have tried as below.
login.jsp
<input type="checkbox" name="_spring_security_remember_me"/>remember-me
applicationContext-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:s="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
<description>SpringSecurity安全配置</description>
<!-- http安全配置 -->
<s:http auto-config="true" use-expressions="true" >
<s:intercept-url pattern="/css/**" filters="none" />
<s:intercept-url pattern="/img/**" filters="none" />
<s:intercept-url pattern="/js/**" filters="none" />
<s:intercept-url pattern="/account/user!save*" access="hasAnyRole('ROLE_修改用户')" />
<s:intercept-url pattern="/account/user!delete*" access="hasAnyRole('ROLE_修改用户')" />
<s:intercept-url pattern="/account/user*" access="hasAnyRole('ROLE_浏览用户')" />
<s:intercept-url pattern="/account/role!save*" access="hasAnyRole('ROLE_修改角色')" />
<s:intercept-url pattern="/account/role!delete*" access="hasAnyRole('ROLE_修改角色')" />
<s:intercept-url pattern="/account/role*" access="hasAnyRole('ROLE_浏览角色')" />
<s:form-login login-page="/login.action" default-target-url="/" authentication-failure-url="/login.action?error=true" />
<s:logout logout-success-url="/" />
<s:remember-me/>
</s:http>
<!-- 认证配置, 使用userDetailsService提供的用户信息 -->
<s:authentication-manager erase-credentials="false">
<s:authentication-provider user-service-ref="userDetailsService">
<s:password-encoder hash="plaintext" />
</s:authentication-provider>
</s:authentication-manager>
<!-- 项目实现的用户查询服务 -->
<bean id="userDetailsService" class="net.top.system.service.account.UserDetailsServiceImpl" />
</beans>
But no use at all.What else i need to configure in my application.
In order to make an application that is already secured with Spring, needed to add the following to the XML:
<sec:http authentication-manager-ref="authenticationManager">
<sec:intercept-url pattern="/secure/**" access="ROLE_USER" />
<sec:form-login/>
<sec:custom-filter … />
<sec:remember-me
data-source-ref="dataSource"
user-service-ref="userDetailsService"/>
</sec:http>
Note that using “data-source” is not a "must", but it actually declares that you want to use a JDBC persistent token. (In this case, Spring works with PersistentTokenBasedRememberMeServices.) Of course the data source bean has to be declared in the XML.
As documented by Spring , a table names persistent_logins has to exist in the DB.
The “userDetailsService” is a ref to the UserService bean, where the users and passwords are declared. It can be in the XML or point to the DB as well.
In run time, Spring creates a Cookie called SPRING_SECURITY_REMEMBER_ME_COOKIE( ) . It is seen with the “JSESSION” Cookie. It we delete the JSESSION (meaning we open a brand new session, just like reopen the browser) the “remember me” cookie remembers the last login, and creates a new JSESSION.
HTH :-)

Disable Spring Security from spring-security.xml file

Help me with the advice please.
I need to disable/enable spring security on my application by some variable in xml file.
my spring-security.xml file
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http auto-config="true">
<intercept-url pattern="/*" access="ROLE_ADMIN" />
<logout logout-success-url="/mainpage" />
<login login-success-url="/mainpage" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="hey" password="there" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
How can be this perfomed?
Thanks.
security
A request pattern can be mapped to an empty filter chain, by setting this attribute to none. No security will be applied and none of Spring Security's features will be available.
http://static.springsource.org/spring-security/site/docs/3.1.x/reference/appendix-namespace.html#nsa-http-security
so:
<http auto-config="true" security="none">
and as usual the "none" parameter can be a springEL expression (well a subset anyways).
hope this is what you were looking for
EDIT:
forgot to mention that it's a new feature is Spring Security 3.1
http://static.springsource.org/spring-security/site/docs/3.1.x/reference/new-3.1.html#new-3.1-highlevel
EDIT2:
For a more dynamic solution use bean profiles. http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/new-in-3.1.html#d0e1293 and http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/

Handling both form and HTTP basic authentication with different sources

I already have form login and Basic auth working side by side with the help of a DelegatingAuthenticationEntryPoint.
What I'm trying to do is have users coming thru the login form to be authenticated against criteria "A", and have users coming thru the Basic auth requests to be authenticated against criteria "B".
Some of the application's resources are exposed thru a RESTful service (accessible via Basic auth). Instead of having users enter their own credentials to make a REST service call, they can enter generated key/value pairs for use exclusively with the REST service that can later be revoked by the user or by the app administrator.
I would prefer to share as much of my security-specific beans as possible between the two methods of authentication. I know I will need separate UserDetailsServices as the form login queries my users table, and Basic auth will query my service_credentials table.
What is the correct way to achieve this kind of configuration in Spring Security?
Depending on your app and whether you're using Spring Security 3.1, you might be best to split the configuration into multiple filter chains, each with a separate authentication manager defined:
<http pattern="/rest_api/**" create-session="stateless"
authentication-manager-ref="serviceCredsAuthMgr">
<http-basic />
</http>
<http authentication-manager-ref="mainAuthMgr">
<form-login />
</http>
<authentication-manager id="serviceCredsAuthMgr">
<authentication-provider user-service-ref="serviceCredsUserDetailsSvc" />
</authentication-manager>
<authentication-manager id="mainAuthMgr">
<!-- whatever -->
</authentication-manager>
Instead of the pattern attribute you can also use the request-matcher-ref attribute to specify a RequestMatcher instance which will be used to map incoming requests to a particular filter chain. This has a very simple interface, but can allow you to match based on something other than the URL path, such as the Accept header.
With SpringSecurity (3.2.3.RELEASE) work fine form as well as basic auth:
<http pattern="/resources/**" security="none"/>
<http pattern="/webjars/**" security="none"/>
<http pattern="/rest/**" create-session="stateless" use-expressions="true">
<intercept-url pattern="/**" access="isFullyAuthenticated()"/>
<http-basic />
</http>
<http auto-config="true" use-expressions="true">
<http-basic/>
<intercept-url pattern="/login" access="permitAll"/>
<intercept-url pattern="/loginfailed" access="permitAll"/>
<intercept-url pattern="/logout" access="permitAll"/>
<intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/**" access="isAuthenticated()"/>
<form-login login-page="/login" default-target-url="/" authentication-failure-url="/loginfailed"/>
<logout logout-success-url="/logout"/>
<remember-me user-service-ref="userService"/>
</http>
<authentication-manager>
<authentication-provider user-service-ref="userService">
<!--
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT email, password, enabled FROM users WHERE email = ?"
authorities-by-username-query="
SELECT u.email, r.name FROM users u, roles r WHERE u.id = r.user_id and u.email = ?"/>
-->
<!--
<user-service>
<user name="mail#yandex.ru" password="password" authorities="ROLE_USER"/>
<user name="admin#gmail.com" password="admin" authorities="ROLE_ADMIN"/>
</user-service>
-->
</authentication-provider>
</authentication-manager>

Spring Security Config Error while server startup

If I keep remember-me element in security.xml file and startup a server then I got following error.
No UserDetailsService registered.......
If I remove this remember-me element then it works fine.
How to get rid of this error...
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<http auto-config="false" use-expressions="true"
access-denied-page="/login.jsp?error=true" entry-point-ref="authenticationEntryPoint">
<remember-me key="abcdefgh" />
<logout invalidate-session="true" />
<intercept-url pattern="/login.jsp" access="permitAll" />
<intercept-url pattern="/index.jsp" access="permitAll" />
<intercept-url pattern="/pub" access="isAuthenticated()" />
<intercept-url pattern="/*" access="permitAll" />
<custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
</http>
<beans:bean id="authenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"
p:authenticationManager-ref="customAuthenticationManager"
p:authenticationFailureHandler-ref="customAuthenticationFailureHandler"
p:authenticationSuccessHandler-ref="customAuthenticationSuccessHandler" />
<!-- Custom authentication manager. In order to authenticate, username and
password must not be the same -->
<beans:bean id="customAuthenticationManager" class="com.cv.pub.cmgt.framework.security.CustomAuthenticationManager" />
<!-- We just actually need to set the default failure url here -->
<beans:bean id="customAuthenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
p:defaultFailureUrl="/login.jsp?error=true" />
<!-- We just actually need to set the default target url here -->
<beans:bean id="customAuthenticationSuccessHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler"
p:defaultTargetUrl="/pub" />
<!-- The AuthenticationEntryPoint is responsible for redirecting the user
to a particular page, like a login page, whenever the server sends back a
response requiring authentication -->
<!-- See Spring-Security Reference 5.4.1 for more info -->
<beans:bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
p:loginFormUrl="/login.jsp" />
<!-- The tag below has no use but Spring Security needs it to autowire the
parent property of org.springframework.security.authentication.ProviderManager.
Otherwise we get an error A probable bug. This is still under investigation -->
<authentication-manager />
</beans:beans>
Spring Security's provided RememberMeServices requires a UserDetailsService in order to work. This means you have two options:
1) If possible, I recommend this as your best option. Instead of writing a custom AuthenticationProvider, write a custom UserDetailsService. You can find an example UserDetailsService looking at InMemoryDaoImpl You can then wire it similar to the configuration below. Note you would remove your custom AuthenticationManager too.
<http ..>
...
<remember-me key="abcdefgh" />
</http>
<authentication-manager>
<authentication-provider user-service-ref="myUserService"/>
</authentication-manager>
<beans:bean id="myUserService" class="MyUserService"/>
2) Write your own RememberMeServices implementation that does not require a UserDetailsService. You can take a look at TokenBasedRememberMeServices for an example (but it requires UserDetailsService). If you want to use the namespace configuration your RememberMeServices implementation will need to implement LogoutHandler. You can then use the namespace to wire it.
<http ..>
...
<remember-me ref="myRememberMeServices"/>
</http>
<beans:bean id="myRememberMeServices" class="sample.MyRememberMeServices"/>

Spring Security 3.0 - Intercept-URL - All pages require authentication but one

I want any user to be able to submit their name to a volunteer form but only administrators to be able to view any other URL. Unfortunately I don't seem to be able to get this correct. My resources.xml are as follows;
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<http realm = "BumBumTrain Personnel list requires you to login" auto-config="true" use-expressions="true">
<http-basic/>
<intercept-url pattern="/person/volunteer*" access=""/>
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Specifically I am trying to achieve the access settings I described via;
<intercept-url pattern="/person/volunteer*" access=""/>
<intercept-url pattern="/**" access="isAuthenticated()" />
Could someone please describe how to use intercept-url to achieve the outcome I've described?
Thanks
Gav
For whatever reason in a grails app I needed;
<intercept-url pattern="/person/volunteer/**" access="" filters="none"/>
<intercept-url pattern="/images/**" access="" filters="none"/>
<intercept-url pattern="/css/**" access="" filters="none"/>
<intercept-url pattern="/js/**" access="" filters="none"/>
<intercept-url pattern="/**" access="ROLE_ADMIN" />
To get this to work, note the difference in the first rule.
What exactly does not work as you expect? what goes wrong?
I think access="" does not what you expect... Use the format from the docs:
<intercept-url pattern="/login.jsp*" filters="none"/>
If you don't use the default authentication (which you do) you would need to add a WebExpressionVoter because you use expressions expressions doc
Hi replace access="" with access="permitAll" for the url you want to make accessile without authentication.

Resources