I am trying to use spring security with two login page and configure two different http section in my spring-security.xml I also have two authentication-manager which handles authentication using custom UserDetailsService.
Below are my code snippets
spring-security.xml
<!-- http Section for Admins -->
<http auto-config="true" use-expressions="true" authentication-manager-ref="adminAuth" pattern="/admin/**">
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login login-page="/adminLogin" default-target-url="/admin/home" authentication-failure-url="/views/homePages/adminHome" username-parameter="username"
password-parameter="password"
login-processing-url="/authenticateAdmin" />
<logout logout-success-url="/login?logout" />
<!-- enable csrf protection -->
<csrf disabled="true"/>
</http>
<authentication-manager id="adminAuth" alias="adminAuth">
<authentication-provider user-service-ref='adminAuthService'>
<password-encoder hash="md5" />
</authentication-provider>
</authentication-manager>
<beans:bean id="adminAuthService" class="security.AdminAuth">
</beans:bean>
<!-- http Section for Students -->
<http auto-config="true" use-expressions="true" authentication-manager-ref="studentAuth" pattern="/student/**" >
<intercept-url pattern="/**" access="hasRole('ROLE_STUDENT')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login login-page="/studentLogin" default-target-url="/student/home" authentication-failure-url="/studentLogin" login-processing-url="/authenticateStudent" />
<logout logout-success-url="/studentLogin" />
<!-- enable csrf protection -->
<csrf disabled="true"/>
</http>
<authentication-manager id="studentAuth" alias="studentAuth">
<authentication-provider user-service-ref='studentAuthService'>
<password-encoder hash="md5" />
</authentication-provider>
</authentication-manager>
<beans:bean id="studentAuthService" class="security.StudentAuth">
</beans:bean>
UserDetailService implementor class
package security;
#Service
public class AdminAuth implements UserDetailsService {
#Autowired
AdminService adminService;
public UserDetails loadUserByUsername(String authAttribute) throws UsernameNotFoundException {
Admin admin = getAdminByUname(authAttribute);
List<SimpleGrantedAuthority> authList = new ArrayList();
authList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
User user = new User(authAttribute, admin.getPassword(), authList);
return user;
}
private Admin getAdminByUname(String authAttribute) {
Admin admin = adminService.getAdminbyUname(authAttribute);
return admin;
}
}
Admin login page
<h2 class="text-center">Staff Login</h2>
<form class="login-form" action="/authenticateAdmin" method="POST">
<div class="form-group">
<label for="exampleInputEmail1" class="text-uppercase">Username</label> <input type="text" class="form-control" placeholder="Email or Mobile" id="username">
</div>
<div class="form-group">
<label for="exampleInputPassword1" class="text-uppercase">Password</label> <input type="password" class="form-control" placeholder="" id="password">
</div>
<div class="form-check">
<label class="form-check-label"> <input type="checkbox" class="form-check-input"> <small>Remember Me</small>
</label>
<button type="submit" class="btn btn-login float-right">Submit</button>
</div>
</form>
Now when I open login page enter username/password and hit login then my loadUserByUsername is not getting invoked.
What I doing wrong here.
Related
I am new to spring. I am creating a spring mvc app. I have a admin url "/admin/".If I login with user credentials with ROLE_ADMIN then I can access the admin page. Right now this scenario is working fine. But If I have not logged in with ROLE_ADMIN and I try to access /admin/ url spring security is redirecting me to /login page.
Here what I want to not expose to outer world that /admin/(or admin url exists) url need authentication. And I want to show default exception page or home page if someone who is not authorized try to access /admin/ url.
Also I need to have custom "/login" url like "/custom_url/" instead of "/login"
But right now I don't have any idea how to achieve this. Any help is appreciated.
applicationContext.xml
</bean>
<security:http auto-config="true">
<security:intercept-url pattern="/admin/**"
access="hasRole('ROLE_ADMIN')" />
<security:form-login
login-page="/login"
default-target-url="/admin"
always-use-default-target="true"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<security:logout logout-success-url="/" invalidate-session="true" logout-
url="/logout" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource"
authorities-by-username-query="SELECT
username, authority From authorities WHERE username = ?"
users-by-username-query="SELECT
username, password, enabled FROM users WHERE username = ?" />
</security:authentication-provider>
</security:authentication-manager>
Login Controller
#RequestMapping("/login")
public String login(#RequestParam(value="error", required = false) String
error, #RequestParam(value="logout",
required = false) String logout, Model model) {
if (error!=null) {
model.addAttribute("error", "Invalid username and password");
}
if(logout!=null) {
model.addAttribute("msg", "You have been logged out successfully.");
}
return "login";
}
login.jsp
<c:if test="${not empty msg}">
<div class="msg">${msg}</div>
</c:if>
<form name="loginForm" action="<c:url
value="/j_spring_security_check" />" method="post">
<c:if test="${not empty error}">
<div class="error" style="color: #ff0000;">${error}</div>
</c:if>
<div class="form-group">
<label for="username">User: </label>
<input type="text" id="username" name="username"
class="form-control" />
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" id="password" name="password"
class="form-control" />
</div>
<input type="submit" value="Submit" class="btn btn-default">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
I am using Spring security 4.
Change the authentication-failure-url="/login?error" to authentication-failure-url="/". This will redirect you to Home page.
The correct xml-snippet in applicationContext.xml is as following:
<security:form-login
login-page="/login"
default-target-url="/admin"
always-use-default-target="true"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/"
username-parameter="username"
password-parameter="password" />
Note: You can change value of authentication-failure-url attribute to an exception page as per need.
I have a Spring rest service, and I'm trying to add security to it. I followed this tutorial, but when I try to access the service directly I get the following error:
There was an unexpected error (type=Internal Server Error,
status=500). Failed to evaluate expression 'ROLE_USER'
Here's my security configuration:
webSecurityConfig.xml
<http entry-point-ref="restAuthenticationEntryPoint">
<intercept-url pattern="/**" access="ROLE_USER"/>
<form-login
authentication-success-handler-ref="mySuccessHandler"
authentication-failure-handler-ref="myFailureHandler"
/>
<logout />
</http>
<beans:bean id="mySuccessHandler"
class="com.eficid.cloud.security.rest.AuthenticationSuccessHandler"/>
<beans:bean id="myFailureHandler" class=
"org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"/>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="temp" password="temp" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
SpringSecurityConfig:
public class SpringSecurityConfig {
public SpringSecurityConfig() {
super();
}
}
I'm also getting this error when trying to use curl to log in:
{
"timestamp":1460399841286,
"status":403,"error":"Forbidden",
"message":"Could not verify the provided CSRF token because your session was not found.",
"path":"/spring-security-rest/login"
}
Do I need to add the csrf token manually to the command? The service has a self-signed certificate, if that makes any difference.
If you don't need CRF to be enabled, then you can disable it in webSecurityConfig.xml file like below:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/login.html" access="hasRole('ANONYMOUS')" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<!-- This form is a default form that used to login
<http-basic/>
-->
<form-login login-page="/login.html"/>
<csrf disabled="true"/>
</http>
If CSRF is enabled, you have to include a _csrf.token in the page you want to login or logout.The below code needs to be added to the form:
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
You need hasRole('ROLE_USER') in the intercept-url element.
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
See the docs for the other expressions, that you can use.
Spring security blocks POST requests.
To enable it you can either:
Add after all you forms requests :
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" class="form-control" />
(For example:
<form id="computerForm" action="addComputer" method="POST">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" class="form-control" />
)
Or if you use anotation, you can allow POST directly in your code by adding the csrf().disable on your WebSecurityConfigurerAdapter (I havent found the xml equivalent yet) :
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.and().formLogin()
.csrf().disable()
;}
I am new at Spring mvc. I am working on a webpage on which users will be able to log in after they have registered and activated themselves.
I sucessfully implemented the Login part, it works fine.
I would like to check if the user has already activated his/her accout via email before the login process launches. Is it possible?
I have tried to solve it with a Login interceptor, but it seems the default "/j_spring_security_check" can not be intercepted. Except this link the interceptor works with all of the url-s.
Is it possible to intercept this default link?
My spring-security.xml
...
<http use-expressions="true">
<intercept-url pattern="/admin**" access="hasRole('ADMIN')" />
<access-denied-handler error-page="/403" />
<form-login login-page="/login"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password"/>
<logout logout-success-url="/login?logout" />
<!--enable csrf protection-->
<csrf />
</http>
<authentication-manager>
<authentication-provider user-service-ref="loginService" />
</authentication-manager>
LoginService
#Service("loginService")
public class LoginServiceImpl implements UserDetailsService {
//It is a regular UserDetailsService nothing extra stuff and works fine
...
}
Login.jsp
....
<div id="login-box">
<span style="color: red">${message}</span>
<c:url value="/j_spring_security_check" var="loginUrl"/>
<form name='f' action="${loginUrl}" method="post">
<p>
<label for="username">Email</label>
<input type="text" id="username" name="username"/>
</p>
<p>
<label for="password">Password</label>
<input type="password" id="password" name="password"/>
</p>
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
<button type="submit" class="btn">Log in</button>
</form>
</div>
...
mvc-dispatcher-servlet.xml
...
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/j_spring_security_check"/>
<bean id="logininterceptor" class="org.psi.controller.LoginInterCeptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
...
LoginInterceptor
public class LoginInterCeptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//Do some check
System.out.println("some check");
return true;
}
}
Any other possible solution are welcome.
I would accomplish this by using either the locked or enabled property on the UserDetails object and let Spring handle the rest rather than trying to intercept the request. When the user confirms their email via the link you send them, flip the flag in the database to indicate the the user is either enabled or not locked.
Alternatively, if you really want to go the intercept route, what I might do is have the login form point to something other than j_spring_security_check, intercept whatever that is, and then (if desired) forward the request to j_spring_security_check. I'm not sure if you can actually override that url.
I am using Spring Roo and I setup my Spring Security like this (applicationContext-security.xml):
<?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 security configurations -->
<http auto-config="true" use-expressions="true" request-matcher="regex">
<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" />
<intercept-url pattern="\A/hotels\?form.*\Z" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/**" access="permitAll"/>
</http>
<!-- Configure Authentication mechanism -->
<authentication-manager alias="authenticationManager">
<!-- SHA-256 values can be produced using 'echo -n your_desired_password | sha256sum' (using normal *nix environments) -->
<authentication-provider>
<password-encoder hash="sha-256">
<!-- <salt-source user-property="login"/> -->
</password-encoder>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
SELECT login, password, enabled
FROM user WHERE login = ?"
authorities-by-username-query="
FROM user u, role r,
user_role ur
WHERE u.id = ur.user
AND r.id = ur.role
AND u.login = ?"
/>
<user-service>
<user name="admin" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918" authorities="ROLE_ADMIN" />
<user name="user" password="04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Then I created a dummy user with the login johnny and the password admin, which is stored in the database like this 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918.
This is the default login page provided by the framework:
<div xmlns:spring="http://www.springframework.org/tags" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<jsp:output omit-xml-declaration="yes" />
<spring:message code="security_login_title" var="title" htmlEscape="false" />
<util:panel id="title" title="${title}">
<c:if test="${not empty param.login_error}">
<div class="errors">
<p>
<spring:message code="security_login_unsuccessful" />
<c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
.
</p>
</div>
<br/>
</c:if>
<c:if test="${empty param.login_error}">
<p>
<!-- <spring:message code="security_login_message" /> -->
</p>
</c:if>
<spring:url value="/resources/j_spring_security_check" var="form_url" />
<form name="f" action="${fn:escapeXml(form_url)}" method="POST">
<input type="hidden" name="test"/>
<div>
<label for="j_username">
<spring:message code="security_login_form_name" />
</label>
<input id="j_username" type='text' name='j_username' style="width:150px" />
<spring:message code="security_login_form_name_message" var="name_msg" htmlEscape="false" />
<script type="text/javascript">
<c:set var="sec_name_msg">
<spring:escapeBody javaScriptEscape="true">${name_msg}</spring:escapeBody>
</c:set>
Spring.addDecoration(new Spring.ElementDecoration({elementId : "j_username", widgetType : "dijit.form.ValidationTextBox", widgetAttrs : {promptMessage: "${sec_name_msg}", required : true}}));
</script>
</div>
<br />
<div>
<label for="j_password">
<spring:message code="security_login_form_password" />
</label>
<input id="j_password" type='password' name='j_password' style="width:150px" />
<spring:message code="security_login_form_password_message" var="pwd_msg" htmlEscape="false" />
<script type="text/javascript">
<c:set var="sec_pwd_msg">
<spring:escapeBody javaScriptEscape="true">${pwd_msg}</spring:escapeBody>
</c:set>
Spring.addDecoration(new Spring.ElementDecoration({elementId : "j_password", widgetType : "dijit.form.ValidationTextBox", widgetAttrs : {promptMessage: "${sec_pwd_msg}", required : true}}));
</script>
</div>
<br />
<div class="submit">
<script type="text/javascript">Spring.addDecoration(new Spring.ValidateAllDecoration({elementId:'proceed', event:'onclick'}));</script>
<spring:message code="button_submit" var="submit_label" htmlEscape="false" />
<input id="proceed" type="submit" value="${fn:escapeXml(submit_label)}" />
<spring:message code="button_reset" var="reset_label" htmlEscape="false" />
<input id="reset" type="reset" value="${fn:escapeXml(reset_label)}" />
</div>
</form>
</util:panel>
</div>
However, when I try to log in I get a Bad credentials error. What is happening?
I can't really manage to find a way of how to debug this because it's all happening internally in spring security I guess so I can't get to know what queries are actually being made and I can't/don't know where to look to figure out why this is failing.
Look at the debug log output when you try to authenticate as the user (always a good idea). Most likely it says it can't find the user "johnny".
This is most likely because you have both a jdbc-user-service and a user-service in the same authentication-provider which won't work.
Use two separate authentication-provider elements:
<authentication-provider>
<jdbc-user-service ... />
</authentication-provider>
<authentication-provider>
<user-service>
....
</user-service>
</authentication-provider>
Also, as I said in your other question, you shouldn't use SHA as a password hashing algorithm unless it's for a legacy system.
After more suffering I managed to solve it. I made the user and role entities-tables again and re-wrote the queries:
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT u.login, u.password, u.enabled from users u where u.login=?"
authorities-by-username-query="SELECT u.login, r.name FROM users u left join user_roles ur on u.id=ur.user join roles r on ur.roles=r.id WHERE u.login=?"
/>
Using two separte authentication-provide had nothing to do with my error.
I have this problem:
in a java web-app (with spring and spring-security 3.1.4) there's a sso authentication; this means the user authenticates as soon as he log in on his pc.
The configuration is this:
<sec:http>
<sec:logout />
<sec:form-login login-page="/login.jsp" default-target-url="/" />
<sec:anonymous username="guest" granted-authority="ROLE_GUEST" />
<sec:custom-filter ref="headersFilter" after="SECURITY_CONTEXT_FILTER" />
<sec:custom-filter ref="jaasFilter" after="SERVLET_API_SUPPORT_FILTER" />
</sec:http>
and this works (actually login.jsp doesn't exist because the user is already logged in as I said above).
Now the problem is that I want to have a "backdoor";this means there should be a login page for me and my team to test and mantain the app.
It should work like this:
-I call localhost/wepapp/myloginpage and I should see the myloginpage.jsp (this works now);
-I click on "login" button and I enter in the second " element" and if the login is ok then I should get redirected to "/" (this doesn't work and I'm simply redirected on "login");
-with the configuration below it seems that I can see "/" without authentication, too, if I call it (localhost/wepapp)
I tried this configuration but it doesn't work, I mean I can see "/" without authentication and I get redirected to login (I also tried other small variations but same result, more or less):
<sec:http pattern="/myloginpage">
<sec:logout />
<sec:form-login login-page="/myloginpage" default-target-url="/" />
</sec:http>
<sec:http pattern="/login">
<sec:logout />
<sec:form-login login-page="/login" default-target-url="/" />
<sec:anonymous username="guest" granted-authority="ROLE_GUEST" />
<sec:custom-filter ref="headersFilter" after="SECURITY_CONTEXT_FILTER" />
<sec:custom-filter ref="jaasFilter" after="SERVLET_API_SUPPORT_FILTER" />
</sec:http>
My myloginpage.jsp:
<form action="login" method="POST">
<table>
<tr>
<td>
Name
</td>
<td>
<input type="text" name="name">
</td>
</tr>
.........
</form>
I also have the controller for myloginpage:
#Controller
public class Myloginpage {
publicMyloginpage() {
}
#RequestMapping("/myloginpage")
public String home() {
return "myloginpage";
}
}
Thankx,
Adrian
It seems you are missing the <intercept-url> tags to configure access to certain paths.
<sec:intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<sec:intercept-url pattern="/secure/**" access="ROLE_USER" />