spring security roles issues - spring

I want to have to types os users (admin and user)
This is my 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.1.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" access-denied-page="/jsp/static/deniedpage.jsp">
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/jsp/static/**" access="isAuthenticated()" />
<intercept-url pattern="/jsp/users/**" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/jsp/admin/**" access="hasRole('ROLE_ADMIN')" />
<logout invalidate-session="true" logout-success-url="/login" logout-url="/logout" />
<form-login login-page="/login" default-target-url="/index" authentication-failure-url="/login?error=true" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select username,password, enabled from Users where USERNAME=?"
authorities-by-username-query="select u.username, ur.authority from USERS u, USER_ROLES ur where u.user_id= ur.user_id and u.username=?" />
</authentication-provider>
</authentication-manager>
<global-method-security secured-annotations="enabled" />
And this is my LoginController
#Controller
public class LoginController {
#RequestMapping(value = "/index", method = RequestMethod.GET)
public String accessUserPage(Model model) {
model.addAttribute("message",
"This page is publicly accessible. No authentication is required to view.");
return "/users/menu";
}
#RequestMapping("/admin/menuAdmin")
public String accessSecuredPage(Model model) {
model.addAttribute("message",
"Only you are authenticated and authorized to view this page.");
return "/admin/menuAdmin";
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(ModelMap model) {
return "login";
}
#RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginerror(ModelMap model) {
model.addAttribute("error", "true");
return "login";
}
#RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logout(ModelMap model) {
return "login";
}
Now everytime i'm making the login he goes to that path /jsp/users/menu even if it is the Role_Admin
As you can see i have differents paths
<intercept-url pattern="/jsp/static/**" access="isAuthenticated()" />
<intercept-url pattern="/jsp/users/**" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/jsp/admin/**" access="hasRole('ROLE_ADMIN')" />
What's wrong with my code? The login works but not the way i want
Thanks

Your intercept-URL are wrong.
The pattern should not match the paths to the jsp file , but your URL path. You should write something like this .
<intercept-url pattern="/index" access="hasRole('ROLE_USER')">
<intercept-url pattern="/admin/menuAdmin" access="hasRole('ROLE_ADMIN')">

Related

Spring security jdbc config to auth user with multiple roles

I am currently working on a java based invoice app.
What I need is , to auth a user with multiple Roles, e.g Peter should have role ROLE_SETTING,ROLE_REPORT,ROLE_QUOTE, while Anne only has one role ROLE_SETTING etc...
Here is my spring-security-config.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.2.xsd">
<http auto-config="true">
<access-denied-handler error-page="/403page" />
<intercept-url pattern="/makebill*" access="ROLE_ADMIN,ROLE_MAKEBILL" />
<intercept-url pattern="/report*" access="ROLE_ADMIN,ROLE_REPORT" />
<intercept-url pattern="/stock*" access="ROLE_ADMIN,ROLE_STOCK" />
<intercept-url pattern="/customer*" access="ROLE_ADMIN,ROLE_CUSTOMER" />
<!-- <intercept-url pattern="/setting*" access="ROLE_ADMIN,ROLE_SETTING" /> -->
<intercept-url pattern="/mainmenu*" access="ROLE_ADMIN,ROLE_MAKEBILL,ROLE_SETTING,ROLE_CUSTOMER,ROLE_REPORT,ROLE_STOCK" />
<form-login
login-page='/login' username-parameter="username"
password-parameter="password" default-target-url="/mainmenu"
authentication-failure-url="/login?authfailed" />
<logout logout-success-url="/login?logout" />
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service
data-source-ref="dataSource"
users-by-username-query="select username,password, enabled from person where username=?"
authorities-by-username-query="select username, role from person, role where username =? " />
</authentication-provider>
</authentication-manager>
</beans:beans>
the authentication-manager currently working fine with just one role, what i mean is...when the sql query authorities-by-username-query="select username, role from person, role where username =? " runs, if the returned value is just one role, e.g ROLE_REPORT, the application works fine, but if have a record in db like, ROLE_REPORT,ROLE_SETTING,ROLE_CUSTOMER , when the query retrieves this value, the application will return me 404 error, it seems I won't be able to grant a user with multiple roles.
Can anyone please point me out what I have done wrong.
Thanks.
I found a solution myself, implemented my own UserDetails, here are the code
#Service("assembler")
public class Assembler {
#Transactional(readOnly = true)
User buildUserFromUserEntity(Person person) {
String username = person.getUsername();
String password = person.getPassword();
boolean enabled = true;
List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
String[] authStrings = person.getRole().split(",");
for(String authString : authStrings) {
System.out.println("all auth roles: " + authString);
authorities.add(new SimpleGrantedAuthority(authString));
}
User user = new User(username, password, enabled,
true, true, true, authorities);
return user;
}
}
#Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired private PersonService personService;
#Autowired private Assembler assembler;
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
UserDetails userDetails = null;
Person person = null;
List<Person> listPeople = personService.listPeople();
for (Person p: listPeople) {
if (p.getUsername().equals(username)) {
person = p;
}
}
if (person == null)
throw new UsernameNotFoundException("user not found");
return assembler.buildUserFromUserEntity(person);
}
}
and here is the spring-security-config.xml
<http auto-config="true">
<access-denied-handler error-page="/403page" />
<intercept-url pattern="/makebill*" access="ROLE_ADMIN,ROLE_MAKEBILL" />
<intercept-url pattern="/report*" access="ROLE_ADMIN,ROLE_REPORT" />
<intercept-url pattern="/stock*" access="ROLE_ADMIN,ROLE_STOCK" />
<intercept-url pattern="/customer*" access="ROLE_ADMIN,ROLE_CUSTOMER" />
<intercept-url pattern="/setting*" access="ROLE_ADMIN,ROLE_SETTING" />
<intercept-url pattern="/mainmenu*" access="ROLE_ADMIN,ROLE_MAKEBILL,ROLE_SETTING,ROLE_CUSTOMER,ROLE_REPORT,ROLE_STOCK" />
<form-login
login-page='/login' username-parameter="username"
password-parameter="password" default-target-url="/mainmenu"
authentication-failure-url="/login?authfailed" />
<logout logout-success-url="/login?logout" />
</http>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
<beans:bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="daoAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
</authentication-provider>
</authentication-manager>
I am now able to assign multiple roles to a single user perfectly.
Thanks for reading :)

After submit login form request goes to get Access Denied spring security

I am facing a weird problem, When I write
<intercept-url pattern="/user/**" access="hasRole('ROLE_USER')" />
it works fine but I change it to
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
it goes directly to 403 page.
Here is my spring security configuration:
<http pattern="/api/**" security="none"/>
<http pattern="/login" security="none"/>
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin*" access="hasRole('ROLE_ADMIN')"/>
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login login-page="/login" authentication-failure-url="/login?error"
username-parameter="username" password-parameter="password"
authentication-success-handler-ref="myAuthenticationSuccessHandler"/>
<logout logout-success-url="/login?logout" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<!-- enable csrf protection -->
<csrf />
</http>
<authentication-manager>
<authentication-provider user-service-ref="loginService" />
</authentication-manager>
My Custom UserDetailsService:
package com.dynamic.spring.service;
#Service("loginService")
public class LoginServiceImpl implements UserDetailsService {
#Autowired
LoginDao loginDao;
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
Users user = loginDao.findByUserName(username);
//problem
List<GrantedAuthority> authorities = buildUserAuthority(user
.getUserRole());
return buildUserForAuthentication(user, authorities);
}
private User buildUserForAuthentication(Users user,
List<GrantedAuthority> authorities) {
return new User(user.getUser_email(), user.getPassword(),
user.isEnabled(), true, true, true, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
// Build user's authorities
for (UserRole userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
}
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(
setAuths);
return Result;
}
and LoginDaoImp:
#Override
public Users findByUserName(String username) {
session = sessionFactory.openSession();
tx = session.getTransaction();
session.beginTransaction();
Users user = (Users) session.createQuery("From Users where User_email=:username")
.setParameter("username", username)
.uniqueResult();
tx.commit();
return user;
}
Kindly anyone help me I am stuck.
Thanks.

Return Http Status (eg. 401) or redirect Spring Security

Hi I use this configuration to Spring Security:
<http auto-config="true" use-expressions="true">
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
<form-login login-page="/login" login-processing-url="/resources/j_spring_security_check" authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/resources/j_spring_security_logout"/>
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
I need to return an Http Error Code like 401 if the Content-Type in my header's request is: application/json; otherwise I want to redirect to Login Page.
But with this configuration, regardless of request content type I'm being redirected to login url with a 302 response code..
Is there a way to do this??
EDIT:
I want use only one servlet to handler the html and json so I try this:
#Component
public class CustomEntryPoint extends LoginUrlAuthenticationEntryPoint {
private final Logger log = LoggerFactory.getLogger(CustomEntryPoint.class);
public CustomEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
if(request.getContentType() != null && request.getContentType().equals("application/json")) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied");
}else {
super.commence(request, response, authException);
}
}
}
And this is my new Security Configuration:
<http auto-config="true" use-expressions="true" entry-point-ref="customEntryPoint">
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
<form-login login-page="/login" login-processing-url="/resources/j_spring_security_check" authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/resources/j_spring_security_logout"/>
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
<beans:bean id="customEntryPoint" class="x.x.CustomEntryPoint">
<beans:constructor-arg value="/login"/>
</beans:bean>
What do you think about that? It is a correct way to do it, or do you know a better way?
Thank you
I solved in this way:
public class CustomEntryPoint extends LoginUrlAuthenticationEntryPoint {
private static final String XML_HTTP_REQUEST = "XMLHttpRequest";
private static final String X_REQUESTED_WITH = "X-Requested-With";
public CustomEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
if (XML_HTTP_REQUEST.equals(request.getHeader(X_REQUESTED_WITH))) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
} else {
super.commence(request, response, exception);
}
}
}
And Security configuration is:
<http auto-config="true" use-expressions="true" entry-point-ref="customEntryPoint">
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
<form-login login-page="/login" login-processing-url="/resources/j_spring_security_check" authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/resources/j_spring_security_logout"/>
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
<beans:bean id="customEntryPoint" class="x.x.CustomEntryPoint">
<beans:constructor-arg value="/login"/>
</beans:bean>

Spring Auto Login Intercept URL issue

I'm able to use the below to store a user in the SecurityContext and I get a valid Authentcation object (says im authenticated and has user_role attached) but then I still get routed to my /auth/login.html page. I stepped the code below and it is returning the "/registered/home.html" to JSF but for some reason when Spring applies the intercept rule to /registered/* it must see it as being an unauthenticated request. Any ideas?
#Named
#Scope("request")
public class SignUpDetail extends BaseAction{
#Inject
private SignUpDetailBean signUpDetailBean;
#Inject
private UserManager userManager;
#Inject #Named("am")
protected AuthenticationManager authenticationManager;
public String login(){
if(signUpDetailBean.getEmail() != null){
Users currentUser = userManager.getUser(signUpDetailBean.getEmail());
authenticateUserAndSetSession(currentUser, (HttpServletRequest) FacesUtils.getExternalContext().getRequest());
return "/registered/home.html";
}else{
return "/auth/login.html";
}
}
private void authenticateUserAndSetSession(Users user,
HttpServletRequest request)
{
UserDetails details = userManager.loadUserByUsername(user.getUsername());
UsernamePasswordAuthenticationToken usernameAndPassword =
new UsernamePasswordAuthenticationToken(
user.getUsername(), "pwd", details.getAuthorities());
// Authenticate, just to be sure
Authentication auth = authenticationManager.authenticate(usernameAndPassword);
// Place the new Authentication object in the security context.
SecurityContextHolder.getContext().setAuthentication(auth);
}
<context:annotation-config />
<context:component-scan base-package="dc" />
<global-method-security />
<http security="none" pattern="/javax.faces.resource/**" />
<http security="none" pattern="/services/rest-api/1.0/**" />
<http security="none" pattern="/preregistered/*" />
<http access-denied-page="/auth/denied.html">
<intercept-url
pattern="/**/*.xhtml"
access="ROLE_NONE_GETS_ACCESS" />
<intercept-url
pattern="/auth/**"
access="ROLE_ANONYMOUS,ROLE_USER" />
<intercept-url
pattern="/auth/*"
access="ROLE_ANONYMOUS" />
<intercept-url
pattern="/registered/*"
access="ROLE_USER" />
<intercept-url
pattern="/*"
access="ROLE_ANONYMOUS" />
<form-login
login-processing-url="/j_spring_security_check.html"
login-page="/auth/login.html"
default-target-url="/registered/home.html"
authentication-failure-url="/auth/login.html" />
<logout invalidate-session="true"
logout-success-url="/"
logout-url="/auth/logout.html"/>
<anonymous username="guest" granted-authority="ROLE_ANONYMOUS"/>
<remember-me user-service-ref="userManager" key="dfdf"/>
</http>
<!-- Configure the authentication provider -->
<authentication-manager alias="am">
<authentication-provider user-service-ref="userManager">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
Store the context object in session since you have set that particular url http security to none
...
HttpSession session = request.getSession();
...
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(auth);
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, context);

Verify Spring Security Login Credentials

My web application is using Spring Security but it returning a BadCredentialsException when processing a form based login. The credentials entered by the user match exactly whats in the database and I don't see the Spring code that compares the j_password value against that of the Users.getPassword from the db, any ideas on how to troubleshoot this? I want to see what its comparing to throw the BadCredentialsException. When I use a hardcoded Below is an outline of my implementation hoping someone can spot my error. Thanks for the assistance!
public static Users getLoggedInUser() {
Users user = null;
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.isAuthenticated()) {
Object principal = auth.getPrincipal();
if (principal instanceof Users) {
user = (Users) principal;
}
}
return user;
}
security context file(removed the xml and schema definitions):
<global-method-security secured-annotations="enabled">
</global-method-security>
<http security="none" pattern="/services/rest-api/1.0/**" />
<http security="none" pattern="/preregistered/**" />
<http access-denied-page="/auth/denied.html">
<intercept-url
pattern="/**/*.xhtml"
access="ROLE_NONE_GETS_ACCESS" />
<intercept-url
pattern="/auth/**"
access="ROLE_ANONYMOUS,ROLE_USER" />
<intercept-url
pattern="/auth/*"
access="ROLE_ANONYMOUS" />
<intercept-url
pattern="/**"
access="ROLE_USER" />
<form-login
login-processing-url="/j_spring_security_check.html"
login-page="/auth/login.html"
default-target-url="/registered/home.html"
authentication-failure-url="/auth/login.html?_dc=45" />
<logout logout-url="/auth/logout.html"
logout-success-url="/" />
<anonymous username="guest" granted-authority="ROLE_ANONYMOUS"/>
<remember-me user-service-ref="userManager" key="valid key here"/>
</http>
<!-- Configure the authentication provider -->
<authentication-manager>
<authentication-provider user-service-ref="userManager">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
UserDetails Implementation (Users.java):
public class Users implements Serializable, UserDetails {
public Collection<GrantedAuthority> getAuthorities() {
List<GrantedAuthority> auth = new ArrayList<GrantedAuthority>();
auth.add(new GrantedAuthorityImpl("ROLE_USER"));
return auth;
}
}
user-service-ref="userManager" (UserManagerImpl.java):
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
Users user = null;
try {
user = userDAO.findByUsername(username);
} catch (DataAccessException ex) {
throw new UsernameNotFoundException("Invalid login", ex);
}
if (user == null) {
throw new UsernameNotFoundException("User not found.");
}
return user;
}
It looks like you are storing cleartext password in the database, but using a passwordEncoder in spring-security configuration, which encodes the received password before comparing against the stored one.
it seems for me that you are just starting with Spring Security. Since your question is really generic I cannot say exactly where is your problem. It could be wrong configuration. Maybe something is wrong with database. Or anything else.
I would suggest you to start fixing your problem in the following way:
Simplify your configs as much as you can.
Try to check how you app works with simplest Spring Security configuration.
If it works add features step by step and always check it for problems.
Simple Spring security config could something like this:
<?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/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="true">
<session-management session-fixation-protection="none"/>
<intercept-url pattern="/login.jsp" filters="none"/>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page="/login.jsp" always-use-default-target="true"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="admin" password="pass1" authorities="ROLE_ADMIN, ROLE_USER"/>
<user name="user" password="pass2" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>

Resources