I'm trying to configure my spring-security project for first time but when I try to login I receive a message: "ERR_TOO_MANY_REDIRECTS". May be somewhere under the hood it redirects to admin again, but where?
here is my 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"
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="hasRole('Admin')" />
<intercept-url pattern="/" 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="/login?error=true"
username-parameter="username" 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>
controller class:
#Controller
#RequestMapping("/")
public class HelloController {
#RequestMapping(method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
return "login";
}
#RequestMapping(value="/admin", method = RequestMethod.GET)
public String showAdmin(ModelMap model) {
return "admin";
}
#RequestMapping(value="/login", method=RequestMethod.GET)
public String enter(#ModelAttribute("employee") Employee employee, ModelMap model){
return "redirect:/admin";
}
...
Table with user's login and role looks like:
Employee
|id|login |password |first_name|last_name|mobile_phone|role |
|1 |login1 |password1 |name1 |lname1 |phone1 |User |
|2 |login2 |password2 |name2 |lname2 |phone2 |Admin |
spring security version is 4.0.3.
This is my first experience with spring-mvc and spring-security so the question may be noobie. What is wrong?
The problem is you are simply redirecting to the admin page on the /login resource, which is where it will send people if they are not logged in. Since /admin requires a specific role, it will try to go to the login page if the user is not logged in which you have redirecting back to the admin page, thus creating a loop.
You want to return a view and not redirect back to the admin page.
Related
In my webapp the login page is http://localhost:8080/vsingh/login
I am able to do below
Open tab1 and open the login page
Open tab2 and open the login page
In tab1 login with USER1. User is redirected to homepage. Now open tab2 and login with USER2. Now user is redirected to homepage of USER1.
How can I logout USER1 automatically in this case? Any pointers are appreciated.
PS: I do redirect automatically to homepage is user is already logged in and hits the login page, however in this case, the tab was already open before the user attempted login
#RequestMapping("/login")
public String login() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken) && auth != null) {
return "redirect:userHome";
}
return "login";
}
Spring Security XML
<http auto-config='true' use-expressions="true">
<intercept-url pattern="/*" access="permitAll" />
<access-denied-handler error-page="/login"/>
<form-login login-page="/login"
authentication-failure-handler-ref="customAuthFailureHandler"
username-parameter="username" password-parameter="password"
authentication-success-forward-url="/userHomeX" />
<csrf />
<logout logout-success-url="/logout" />
</http>
<authentication-manager>
<authentication-provider>
<password-encoder ref="encoder" />
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT USERNAME, RTRIM(PASSWORD) AS PASSWORD, CASE WHEN ENABLED=1 AND ADMIN_LOCK = 0 THEN 1 ELSE 0 END AS ENABLED FROM JWBDATABASE.JWBSCHEMA.USERS WHERE USERNAME=?"
authorities-by-username-query="SELECT USERNAME,USER_ROLE AS ROLE FROM JWBDATABASE.JWBSCHEMA.USERS WHERE USERNAME=?" />
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11" />
</beans:bean>
<beans:bean id="customAuthFailureHandler"
class="com.vj.authenticationManager.CustomAuthFailureHandler">
</beans:bean>
Why it is not duplicate?
Question is not about allowing multiple logins in different tabs but somehow force a single login for all tabs. If someone logins thru an already open login page with a different userid, either the old one should be forced logged out or throw an error on new login with some message
Lets say my logout URL is: app/logout.
I need to show a message - "You are succesfully logged out" in logout page only when logout was triggred by clikcing the logout button.
The message should not be displayed if the user enters this URL directly. Any idea how to implement this?
Controller:
#RequestMapping(value ="/logout", method = RequestMethod.GET)
public ModelAndView logout(HttpServletRequest request, HttpServletResponse response) {
ModelAndView model = new ModelAndView();
//some code here to distingish
model.addObject("msg", "You are succesfully logged out!");
model.setViewName("login");
return model;
}
Spring-Security.xml:
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">
<http auto-config="true" create-session="ifRequired" use-expressions="true">
<intercept-url pattern="/logout" access="IS_AUTHENTICATED_REMEMBERED"/>
<form-login
login-page="/login"
default-target-url="/home"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/logout" invalidate-session="true" delete-cookies="JSESSIONID"/>
<!-- enable csrf protection -->
<csrf/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="mkyong" password="123456" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
As it is for Spring Security, I think that the simplest way is to use spring security to restrict /logout to authenticated users.
Using the namespace it would be :
<intercept-url pattern="/logout" access="IS_AUTHENTICATED_REMEMBERED"/>
Using Java configuration, it would be :
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/logout").authenticated()
...
}
Add #RequestParam(value = "foo", required = false) Boolean foo
Add this additional parameter to logout button, if foo exist and is true do your logic
I have trouble in spring security 3.1.
I'm going to use spring security openid-login with gmail, and I want to get user information using attribute-exchange. but if I use it, it is always called when user log-in my website.
How can i call only once at user sign-in my website?
I managed sign-in at openIdAuthFailureHandler, and I want to get user information in this bean...please help me!
(I found security:remember-me, but it doesn't work..)
security.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:global-method-security
secured-annotations="enabled" proxy-target-class="true" />
<security:http auto-config="true" access-denied-page="/denied/accessDenied">
<security:intercept-url pattern="/admin/**"
access="ROLE_ADMIN" />
<security:intercept-url pattern="/reservation/**"
access="ROLE_USER, ROLE_ADMIN" />
<security:intercept-url pattern="/board/**"
access="ROLE_ADMIN, ROLE_USER" />
<security:openid-login login-page="/"
login-processing-url="/j_spring_openid_security_check.do"
authentication-success-handler-ref="customAuthenticationHandler"
authentication-failure-handler-ref="openIdAuthFailureHandler">
<security:attribute-exchange identifier-match="https://www.google.com/.*" >
<security:openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true" />
<security:openid-attribute name="firstname" type="http://axschema.org/namePerson/first" required="true" />
</security:attribute-exchange>
</security:openid-login>
<security:logout logout-url="/j_spring_openid_security_logout.do"
logout-success-url="/" invalidate-session="true" />
<!-- <security:http-basic /> -->
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<!-- <security:user-service properties="/WEB-INF/resources/users.xml"
/> -->
<security:password-encoder ref="passwordEncoder" />
<security:jdbc-user-service id="userDetailsService"
data-source-ref="dataSource"
users-by-username-query="SELECT id as id, passwd as passwd, 1 as enabled FROM user WHERE id=?"
authorities-by-username-query="SELECT id as id, power as authority FROM user WHERE id=?" />
<!-- <security:password-encoder hash="sha-256"></security:password-encoder> -->
</security:authentication-provider>
</security:authentication-manager>
<bean id="customTokenRepository" class="com.jinyoung.reservation.openid.CustomTokenRepository" />
<bean id="openIdAuthFailureHandler" class="com.jinyoung.reservation.openid.OpenIDAuthenticationFailureHandler"/>
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />
</beans>
OpenIDAuthenticationFailureHandler
public class OpenIDAuthenticationFailureHandler extends
SimpleUrlAuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
if (exception instanceof UsernameNotFoundException && exception.getAuthentication() instanceof OpenIDAuthenticationToken && ((OpenIDAuthenticationToken) exception.getAuthentication()).getStatus().equals(OpenIDAuthenticationStatus.SUCCESS)) {
DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
request.getSession(true).setAttribute("USER_OPENID_CREDENTIAL", ((UsernameNotFoundException)exception).getExtraInformation());
OpenIDAuthenticationToken openIdAuth = (OpenIDAuthenticationToken)exception.getAuthentication();
request.getSession(true).setAttribute("USER_OPENID_CREDENTIAL_EXTRA", openIdAuth);
for(OpenIDAttribute attr : openIdAuth.getAttributes()) {
System.out.printf("AX Attribute: %s, Type: %s, Count: %d\n", attr.getName(), attr.getType(), attr.getCount());
for(String value : attr.getValues()) {
System.out.printf(" Value: %s\n", value);
}
}
redirectStrategy.sendRedirect(request, response, "/login/registrationOpenid");
// redirect to create account page
/*redirectStrategy.sendRedirect(request, response,
"/?fail=true");*/
} else {
super.onAuthenticationFailure(request, response, exception);
}
}
}
Ran in to a similar problem which I solved by having two different form targets (j_spring_openid_security_check_signup and j_spring_openid_security_check) for the signup/login page. One used when signing up and one when logging in. In spring-security.xml we use two different configs, one that asks for attributes and one that don't:
<!-- Configure attribute-exchange for signup -->
<!-- will only match /j_spring_openid_security_check_signup -->
<security:http auto-config="true" use-expressions="true" path-type="ant" pattern="/j_spring_openid_security_check_signup">
<security:openid-login
login-processing-url="/j_spring_openid_security_check_signup"
user-service-ref="userDetailsService"
authentication-failure-handler-ref="authenticationFailureHandler"
authentication-success-handler-ref="authenticationSuccessHandler">
<security:attribute-exchange identifier-match="https://www.google.com/.*" >
<security:openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true" />
<security:openid-attribute name="firstname" type="http://axschema.org/namePerson/first" required="true" />
</security:attribute-exchange>
</security:openid-login>
</security:http>
<!-- Skip attribute-exchange at log-in -->
<!-- match everything else -->
<security:http auto-config="true" use-expressions="true" path-type="ant">
<security:openid-login
login-processing-url="/j_spring_openid_security_check"
user-service-ref="userDetailsService"
authentication-failure-handler-ref="authenticationFailureHandler"
authentication-success-handler-ref="authenticationSuccessHandler"
/>
</security:http>
Then in the authenticationSuccessHandler you will have access to attributes while signing in but not at log-in.
-------------------------------I solved!!!------------------------------------------
I modified spring-security-openid-3.1.1.RELEASE.jar, and I call attribute-change only once at user access my site first time. if one who want to know, give me e-mail kjy30532#gmail.com !
I have an application which I have configured so I can use database to authenticate users.
Trying to login as either user or admin with the set up username and password gives this error:
HTTP Status 404 - /project/login_error.jsp
So I tried to see if my url were working manually by putting the links in the navigation bar, the admin page comes up when I use this link:
https://localhost:8443/project/admin
Some other page also come up when entered manually, others do not show but gives me the error page.
The home page on the other hand does not show at all when I use this:
https://localhost:8443/project/home
It does not give any error but just redirects back to the login page.
No error comes up in the stack trace except for the hibernate HQL.
The security config:
<global-method-security pre-post-annotations="enabled" />
<http pattern="/resources/css/**" security="none"/>
<http pattern="/login.jsp*" security="none"/>
<http auto-config="true" use-expressions="true" access-denied-page="/denied"
authentication-manager-ref="authManager">
<intercept-url pattern="/**" requires-channel="https" />
<intercept-url pattern="/index" access="permitAll" requires-
channel='https'/>
<intercept-url pattern="/login" access="permitAll" requires-
channel='https'/>
<intercept-url pattern='/home' access="hasRole('ROLE_USER')" requires-
channel='https'/>
<intercept-url pattern='/admin' access="hasRole('ROLE_ADMIN')" requires-
channel='https'/>
<form-login login-page='/login' login-processing-url='/j_spring_security_check'
always-use-default-target="true" default-target-url="/home" authentication-failure-
url="/login_error.jsp?error=true"/>
<logout invalidate-session="true" logout-success-url='/login' />
</http>
<authentication-manager id="authManager">
<authentication-provider user-service-ref="***UserDetailsService">
<password-encoder hash="md5"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="**UserDetailsService" class="com.**.**.**.**UserDetailsService">
</beans:bean>
Controller
#Controller
public class ApplicationController {
#RequestMapping(value="/home", method = RequestMethod.GET)
public String home(ModelMap model) {
logger.info("Download and Upload Page {}.");
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
#RequestMapping(value="/login", method = RequestMethod.GET)
public String login(ModelMap model) {
logger.info("This is the login page {}.");
return "login";
}
Jsp page
<c:url value="/j_spring_security_check" var="loginUrl"/>
<form action="${loginUrl}" method="post" >
<label for="j_username">Username</label>
<input id="j_username" name="j_username" type="text" />
<label for="j_password">Password</label>
<input id="j_password" name="j_password" type="password" />
<input type="submit"
value="Login"/>
</form>
The HQL that shows in the output
Hibernate: select login0_.person_id as person1_1_, login0_1_.manager_id as
manager4_1_, login0_1_.email as email1_, login0_1_.name as name1_, login0_.enabled
as enabled3_, login0_.password as password3_, login0_.user_id as user5_3_,
login0_.username as username3_ from users login0_ inner join person login0_1_ on
login0_.person_id=login0_1_.person_id where login0_.username=?
I don't really know what I'm missing in this implementation. And I would appreciate any pointers on what the problem is.
Edit - adding security filter
<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>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
When am trying to authenticate the user through LDAP from database am getting the following error.
Reason: Cannot pass null or empty values to constructor.
Can anyone please tell me what am doing wrong?
<?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.1.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_USER,ROLE_ADMIN" />
<intercept-url pattern="/administrator.htm" access="ROLE_ADMIN" />
<!-- <form-login login-page="/dashboard.htm" default-target-url="/dashboard.htm" authentication-failure-url="/ExceptionPage.jsp" /> -->
<form-login/>
</http>
<authentication-manager>
<authentication-provider>
<!-- <user-service>
<user name="20022263" password="da" authorities="ROLE_USER" />
<user name="20039004" password="da" authorities="ROLE_ADMIN" />
</user-service> -->
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT a.GLOBALID AS username, a.PASSWORD AS password, a.Enabled AS enabled FROM EU_MAS_TBUSER a WHERE a.GLOBALID=?"
authorities-by-username-query="select eu.USERNAME AS username, r.ACCESSROLEID AS authority from EU_MAS_TBUSER eu, EU_MAS_TBUSERS_ROLE r where eu.GLOBALID = r.GLOBALID and eu.GLOBALID=?"
role-prefix="ROLE_"/>
</authentication-provider>
</authentication-manager>
</beans:beans>
The actual line that produces the exception is here. The relevant code where the user object is created is here.
So my best guess is that you have a null password field for the user in the database.
Note that if you are posting an error like this it's a lot easier to answer if you give the stacktrace and the relevant debug output from the server log.
HTTP Status 401 : Cannot pass null or empty values to constructor
The server is expecting a query param but you are sending the wrong value in it.
So simpler answer is:
We need to send a valid query param what the server is expecting.