j_spring_security_check not invoke when use specific url pattern in http element - spring

I'm trying to implement two security realms using spring security. I am using Spring security 3.1.4 RELEASE and Spring 3.2.0 RELEASE. In my web application there are two users and they should be authenticate separately. Therefore I tried to use multiple http elements to filter url pattern and redirect to corresponding login page.
Here is my Spring-security.xml.
<beans:beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="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.1.xsd" xmlns:beans="http://www.springframework.org/schema/beans">
<security:http pattern="/admin/**" auto-config="true" use-expressions="true">
<security:form-login login-page="/admin/login" default-target-url="/admin/dashboard"
authentication-failure-url="/admin/loginfailed"/>
<security:logout logout-success-url="/admin/logout"/>
<security:intercept-url pattern="/admin/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<security:intercept-url pattern="/admin/login" access="permitAll"/>
<security:intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')"/>
</security:http>
<security:http pattern="/customer/**" auto-config="true" use-expressions="true">
<security:form-login login-page="/customer/login" default-target-url="/customer/reports"
authentication-failure-url="/customer/loginfailed"/>
<security:logout logout-success-url="/customer/logout"/>
<security:intercept-url pattern="/customer/j_spring_security_check" access="permitAll"/>
<security:intercept-url pattern="/customer/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<security:intercept-url pattern="/customer/login" access="permitAll"/>
<security:intercept-url pattern="/customer/*" access="hasRole('ROLE_ADMIN')"/>
</security:http>
<beans:bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<beans:property name="jndiName">
<beans:value>java:/myDS</beans:value>
</beans:property>
</beans:bean>
<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT login_name AS username, password, 1 AS enabled
FROM tbl_user WHERE login_name=?"
authorities-by-username-query="SELECT login_name , CASE role_id WHEN 2 THEN 'ROLE_USER' WHEN 1 THEN 'ROLE_ADMIN'ELSE '' END AS authority
FROM tbl_user WHERE login_name=?"
/>
</security:authentication-provider>
</security:authentication-manager>
</beans:beans>
Here is my web.xml
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Here is my login.jsp
enter code here
<c:url value="/j_spring_security_check" var="url" />
<form c role="form" action="${url}" method='POST'>
<div>
<label>Email</label>
<div >
<input type="email" name="j_username" id="inputEmail3"
placeholder="Email">
</div>
</div>
<div >
<labe>Password</label>
<div>
<input type="password" name="j_password" id="inputPassword3"
placeholder="Password">
</div>
</div>
<div class="form-group">
<div>
<button type="submit">Sign in</button>
</div>
</div>
</form>
When I remove the url patterns in the http elements, it's perfectly works. Actually I can't remove both url patterns. I tried by removing "/customer/**" and it works for customer login. But when url pattern is present, j_spring_security_check 404 not fount error occurred.
According to the spring security documentation, we can add multiple http elements with different url patterns.
Please help me to find a solution for this.

You can add as many http elements as you want, BUT you will also have to change the login-url accordingly. Currently you haven't changed anything leaving the default /j_spring_security_check in place. Whereas you want a /admin/j_spring_security_check and /customer/j_spring_security_check.
To enable this you will need to configure the login-processing-url on the <form-login /> element, just like you specified the login-page attributes. Do this for each http element.
<security:form-login login-page="/admin/login" login-processing-url="/admin/j_spring_security_check" default-target-url="/admin/dashboard" authentication-failure-url="/admin/loginfailed" />

Related

Can't get Spring security "remember me" feature to work

I'm new to Spring and Java. Trying to set up security remember me feature.
Here is my security.xml and login.jsp files. What am I doing wrong?
security.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="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-4.0.xsd">
<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource"/>
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<security:http use-expressions="true">
<security:intercept-url pattern="/" access="permitAll"/>
<security:intercept-url pattern="/createplayer" access="isAuthenticated()"/>
<security:intercept-url pattern="/players" access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/createaccount" access="permitAll"/>
<security:intercept-url pattern="/login" access="permitAll"/>
<security:intercept-url pattern="/logout" access="permitAll"/>
<security:intercept-url pattern="/welcome" access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/**" access="denyAll"/>
<security:form-login login-page="/login" authentication-failure-url="/login?error=true"/>
<security:remember-me key="MyAppKey" remember-me-parameter="remember-me"
remember-me-cookie="remember-me"
token-validity-seconds="604800"
data-source-ref="dataSource"/>
</security:http>
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
</bean>
</beans>
login.jsp
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
<h1>Login</h1>
<c:if test="${param.error != null}">
Login failed. Check if username or password are correct!
</c:if>
<form action = "/login", method="post">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
Name <br>
<input name="username"/> <br>
Password<br>
<input type="password" name="password"/> <br>
Remember me <br>
<input type="checkbox" name="remember-me">
<br><br>
<input type="submit"> <br><br>
</form>
<h2>${msg}</h2>
<br>
Create account <br>
</body>
</html>
P.S. I tried adding
<session-config>
<session-timeout>1</session-timeout>
</session-config>
to web.xml to check if "remember me" works, but instead it "remembering me" it always logs out in one minute.
Add id to your jdbc-user-service
<security:jdbc-user-service data-source-ref="dataSource" id="jdbcUserService/>
and refer to your service from remember-me by it's id like this:
<security:remember-me key="MyAppKey"
user-service-ref="jdbcUserService"/>

Spring Security sec:authorize throw exception

I want to add a field to my jsp which will be shown only to admin. For this purpose I use tag sec:authorize access="hasRole('Admin')". But when I add it, application throws exception: http://pastebin.com/TcN0k0K0
I use spring 4.1.7.RELEASE, spring-security version 4.0.3.RELEASE. In pom.xml I've added spring-security-taglibs v.4.0.3
here is my jsp code:
<%# taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<html>
<body>
<sec:authorize access="hasRole('Admin')">
<p>Must have ROLE_Admin to see this</p>
</sec:authorize>
<form name='registerForm' method='POST' action="/admin/createuser">
...
in database role stored as ROLE_Admin, ROLE_User
spring-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<http use-expressions="true" >
<csrf disabled="true"/>
<intercept-url pattern="/admin" access="hasAnyRole('Admin', 'User')" />
<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/logout" access="permitAll" />
<access-denied-handler error-page="/403" />
<form-login login-page='/login' login-processing-url="/login" authentication-failure-url="/403"
default-target-url="/admin"
username-parameter="login" password-parameter="password" />
<logout logout-url="/logout" logout-success-url="/logoutSuccessful" delete-cookies="JSESSIONID" invalidate-session="true" />
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="myDataSource"
users-by-username-query= "select login, password, 'true' from employee where login=?"
authorities-by-username-query= "select login, role from employee where login =? " />
</authentication-provider>
</authentication-manager>
<beans:import resource="data-source-cfg.xml"/>
</beans:beans>
How to fix this problem?
take a look at this post, the problem you are getting is about the spring version. You have two options:
1 - To keep using spring security 4.0.3 you must upgrade Spring version for 4.2.x.
2 - To keep using your current spring version you must downgrade to the Spring security 4.0.2
Best Regards

How to show hide elements using spring security

I have a button which i want to show in login page.
So when the user is logged in i want to hide this button. I think
<sec:authorize access="isAuthenticated()">
is useful for this so i included something like following in my jsp
<sec:authorize access="not isAuthenticated()">
<div class="pull-right">
But is not visible in the login page as well as after logged in.
What can be the problem.
<http pattern="/foobar/static-wro4j/**" security="none"/>
<http pattern="/foobar/static/**" security="none"/>
<http pattern="/foobar/login*" security="none"/>
<http pattern="/foobar/syndic/**" security="none"/>
<http pattern="/foobar/register/**" security="none"/>
<http pattern="/foobar/lostpassword/**" security="none"/>
<http auto-config="true" use-expressions="true" create-session="ifRequired">
<remember-me key="foobarRememberKey" token-validity-seconds="2592000"/>
<intercept-url pattern="/foobar/presentation" access="permitAll()"/>
<intercept-url pattern="/foobar/tos" access="permitAll()"/>
<intercept-url pattern="/foobar/license" access="permitAll()"/>
<intercept-url pattern="/foobar/404-error" access="permitAll()"/>
<intercept-url pattern="/foobar/500-error" access="permitAll()"/>
<intercept-url pattern="/foobar/rest/users" method="POST" access="permitAll()"/>
<intercept-url pattern="/metrics/**" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/**" access="isAuthenticated()"/>
<form-login
login-processing-url="/foobar/authentication"
login-page="/foobar/login"
authentication-failure-url="/foobar/login?action=loginFailure"
default-target-url="/foobar/"
authentication-success-handler-ref="foobarAuthenticationSuccessHandler"/>
<http-basic/>
<logout logout-url="/foobar/logout"
logout-success-url="/foobar/login"/>
<openid-login authentication-failure-url="/foobar/login?action=loginFailure"
user-service-ref="openIdAutoRegisteringUserDetailsService">
<!-- Only Google Apps is supported -->
<attribute-exchange identifier-match="https://www.google.com/.*">
<openid-attribute name="email" type="http://axschema.org/contact/email" required="true" count="1"/>
<openid-attribute name="firstname" type="http://axschema.org/namePerson/first" required="true"/>
<openid-attribute name="lastname" type="http://axschema.org/namePerson/last" required="true"/>
</attribute-exchange>
</openid-login>
</http>
Make sure you have included the Spring Security Tag Library in the JSP:
<%# taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
In your security configuration include:
<beans:bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"/>
Then use the authorize tag:
<sec:authorize access="isAuthenticated()">
<!-- Content for Authenticated users -->
</sec:authorize>
<sec:authorize access="isAnonymous()">
<!-- Content for Unauthenticated users -->
</sec:authorize>

Spring security redirection after login

After successfull login, it doesn't redirects to "index.php". It redirects same page which is "login.php". Is there something wrong with my spring-security.xml page?
By the way when I run the application it redirects me to "login.php" which is good. But It doesn't shows primefaces components but html components. After I succesfully login, It redirects the same page but this time It shows Primefaces components instead of html components.
<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.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/pages/login.xhtml*" access="permitAll"/>
<intercept-url pattern="/**" access="hasRole('admin')" />
<form-login login-page='/pages/login.xhtml' default-target-url="/pages/index.xhtml"
authentication-failure-url="/pages/login.xhtml"/>
<logout logout-success-url="/pages/logout.xhtml" />
</http>
<!--Authentication Manager Details -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customUserDetailsService">
<!-- <password-encoder hash="md5"/>-->
</authentication-provider>
</authentication-manager>
my web.xml
<welcome-file-list>
<welcome-file>pages/index.xhtml</welcome-file>
</welcome-file-list>
my login page
<p:outputPanel id="loginOutputPanelId" style="border: navy">
<p:panelGrid id="loginInformationPanel" columns="2">
<h:outputText value="Username: "/>
<p:inputText value="#{loginController.userName}"/>
<h:outputText value="Password: "/>
<p:inputText value="#{loginController.password}"/>
</p:panelGrid>
<p:commandButton value="Login" actionListener="#{loginController.login()}"/>
</p:outputPanel>
my loginController.login() method returns "index" string and my faces.config;
<navigation-rule>
<from-view-id>/pages/login.xhtml</from-view-id>
<navigation-case>
<from-outcome>index</from-outcome>
<to-view-id>/pages/index.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
EDIT:
without component it runs without any problem. When i add form-login it says "The webpage at http://localhost:8080/myApplication/pages/login.xhtml has resulted in too many redirects".
<http auto-config='true' use-expressions="true">
<intercept-url pattern="/**" access="hasRole('admin')" />
<logout logout-success-url="/pages/logout.xhtml" />
<form-login login-page="/pages/login.xhtml"
login-processing-url="/j_spring_security_check"
default-target-url="/pages/index.xhtml"
authentication-failure-url="/pages/login.xhtml"/>
</http>
My login page
<p:outputPanel id="loginOutputPanelId" style="border: navy">
<p:panelGrid id="loginInformationPanel" columns="2">
<h:outputText value="Kullanıcı Adı: "/>
<p:inputText id="j_username" required="true" value="#{loginController.userName}"/>
<h:outputText value="Şifre: "/>
<p:inputText id="j_password" required="true" value="#{loginController.password}"/>
</p:panelGrid>
<p:commandButton id="login" type="submit" ajax="false" value="Login" actionListener="#{loginController.login()}"/>
</p:outputPanel>
My new loginController.login() method;
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
.getRequestDispatcher("/j_spring_security_check");
dispatcher.forward((ServletRequest) context.getRequest(),
(ServletResponse) context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
To force spring-security to go to /pages/index.xhtml, you can use property always-use-default-target as this :
<form-login login-page='/pages/login.xhtml'
default-target-url="/pages/index.xhtml"
always-use-default-target="true"
authentication-failure-url="/pages/login.xhtml"/>
Otherwise, the login page should be shown automatically by spring security when the user calls a secured resource, and once login done, continue to the secured resource it was originally asked for.
In your case, some confusion seems to come from the fact that you want spring security to handle the login, and you try to handle it yourself with a jsf actionListener and navigation rules.
putting "<form-login [...]" in the configuration essentially tells spring to activate a filter (UsernamePasswordAuthenticationFilter) that will listen to requests made to /j_spring_security_check . If you want spring to handle login, by default your form login must request this url, passing two parameters : j_username and j_password .
This way, spring's UsernamePasswordAuthenticationFilter will kick in and try to authenticate the provided credentials using the UserDetailsService you configured in your AuthenticationProvider.
I think you have to remove your jsf controller for login and use spring-security to handle authentication.
Hope this helps.
PS : make sure your web.xml defines the DelegatingFilterProxy before all other servlet filters :
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Please check your Faces Servlet URL pattern in web.xml.
If it contains .jsf like:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
then you must update your code in spring-security.xml like:
<form-login login-page="/pages/login.jsf"
login-processing-url="/j_spring_security_check"
default-target-url="/pages/index.jsf"
authentication-failure-url="/pages/login.jsf"/>

Max Concurrent sessions doesn't apply to same browser

i have configured max sessions to be 1 and set error-if-maximum-exceeded=true
i noticed two issues:
1- session-authentication-error-url doesn't work if there's authentication-failure-handler-ref configured, the authentication-failure-handler-ref takes precedence and then you will have to handle SessionAuthenticationException there and make needed logic.
2- if i have open session in chrome and try to login in firefox i get the SessionAuthenticationException but if i tried to login again in chrome (which already has an open session) i get login successful and doesn't get the SessionAuthenticationException
should i prevent the user from seeing login page if he's already authenticated ?
if that's correct, please advise how to do that.
i usually check for authenticated user as follows:
if(!SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals("anonymousUser")){
// logged in user
}
here's my current configuration:
1- web.xml:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>
2- applicationSecurity.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="passwordEncoder"
class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
<constructor-arg value="256"/>
</bean>
<bean id="saltSource"
class="org.springframework.security.authentication.dao.ReflectionSaltSource">
<property name="userPropertyToUse" value="username" />
</bean>
<bean id="customUserDetailsService"
class="com.myapp.faces.web.services.CustomUserDetailsService" />
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="customUserDetailsService">
<security:password-encoder ref="passwordEncoder">
<security:salt-source ref="saltSource" />
</security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
<bean id="loginSuccessHandler" class="com.myapp.faces.web.services.LoginSuccessHandler">
<property name="defaultTargetUrl" value="/dashboard"/>
</bean>
<bean id="loginFailureHandler" class="com.myapp.faces.web.services.LoginFailureHandler" />
<security:http use-expressions="true" auto-config="true" >
<security:intercept-url pattern="/j_spring_security_check" access="permitAll" />
<security:intercept-url pattern="/faces/javax.faces.resource/**" access="permitAll"/>
<security:intercept-url pattern="/xmlhttp/**" access="permitAll" />
<security:intercept-url pattern="/resources/**" access="permitAll" />
<security:intercept-url pattern="**/faces/javax.faces.resource/**" access="permitAll" />
<security:intercept-url pattern="**/xmlhttp/**" access="permitAll" />
<security:intercept-url pattern="**/resources/**" access="permitAll" />
<security:intercept-url pattern="/login" access="permitAll"/>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:form-login
login-processing-url="/j_spring_security_check"
login-page="/login"
authentication-failure-handler-ref="loginFailureHandler"
authentication-success-handler-ref="loginSuccessHandler" />
<security:logout />
<security:session-management session-authentication-error-url="/login?error=3">
<security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
</security:session-management>
</security:http>
</beans>
I personally do it this way.
#RequestMapping(method=RequestMethod.GET)
public String login(Authentication authentication)
{
if((authentication != null) && authentication.isAuthenticated())
{
return "redirect:dashboard";
}
return viewResolver.getView(ViewConstants.LOGIN_PAGE);
}
The method above is used for requesting the login page.
I don't think there is a way to do it using only configuration though. I may be wrong.
EDIT :
Check this link

Resources