In my Spring project, I have defined my own custom authentication provider. Before bringing in Spring Security, I used BCrypt in Java code and now passwords are saved after BCrypting in Database.
spring-security.xml
<security:authentication-manager>
<security:authentication-provider ref="myAuthenticationProvider">
</security:authentication-provider>
</security:authentication-manager>
<b:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<b:bean id="myAuthenticationProvider" class="com.cT.www.provider.CustomAuthenticationProvider">
</b:bean>
And my custom authentication provider looks as follows.
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
public CustomAuthenticationProvider() {
super();
}
#Autowired
private PersonService personService;
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
System.out.println(authentication.getName() + "principal" +(String) authentication.getCredentials() );
String username = authentication.getName();
String password = (String) authentication.getCredentials();
UserSignUp user = (UserSignUp) personService.loadUserByUsername(username);
if (user == null || !user.getUsername().equalsIgnoreCase(username)) {
throw new BadCredentialsException("Username not found.");
}
if (!password.equals(user.getPassword())) {
throw new BadCredentialsException("Wrong password.");
}
List<Role> authorities = user.getAuthorities();
return new UsernamePasswordAuthenticationToken(user, password, authorities);
}
#Override
public boolean supports(Class<?> arg0) {
// TODO Auto-generated method stub
return true;
}
}
I don't wanna use user-service-ref in spring-security.xml wihtin authentication-manager.
If your user passwords are already saved as BCrypt in database you don't need much of thing to do. In your authenticate method just replace your password checking condition with below
if (BCrypt.checkpw(password, user.getPassword())) {
throw new BadCredentialsException("Wrong password.");
}
Refer BCrypt source for more details.
You can refer to BCryptPasswordEncoder this way:
<authentication-manager>
<authentication-provider>
<password-encoder ref="encoder" />
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11" />
</beans:bean>
For details see http://www.mkyong.com/spring-security/spring-security-password-hashing-example/
Related
this is my spring-security.xml:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/courses*" access="hasRole('ROLE_USER')" />
<custom-filter before="FORM_LOGIN_FILTER" ref="MyAuthFilter" />
<form-login
login-page="/login"
default-target-url="/courses"
authentication-failure-url="/login?error"
username-parameter="loginField"
password-parameter="passwordField" />
<csrf disabled="true" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="ars" password="1234" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
here is MyAuthFilter:
#Component("MyAuthFilter")
public class MyAuthFilter extends UsernamePasswordAuthenticationFilter {
#Autowired
#Qualifier("authenticationManager")
#Override
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
System.out.println("running my own version of UsernmePasswordFilter ... ");
LoginForm loginForm = new LoginForm();
loginForm.setUsername(request.getParameter("login"));
loginForm.setPassword(request.getParameter("password"));
request.setAttribute("error", 3);
System.out.println("login : " + loginForm.getUsername());
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(loginForm.getUsername(), loginForm.getPassword());
setDetails(request, authRequest);
Authentication authResult = this.getAuthenticationManager().authenticate(authRequest);
return authResult;
}
}
When i enter wrong login or password it shows "bad credentials" error instead of redirecting to a login page.Without custom filter it works fine.
I just want to check what wrong with login\password and set "error" wariable, wich i use in login form to show concrete error like " empty pass" etc.
I need to make a login page witch shows concrete error like "empty pass\empty login\ both empty\wrong login or pass". I will be very greatfull if someone could share a link with example or guide for those validation.
Define success and failure handler
#Bean
public AuthenticationSuccessHandler getSuccessHandler(){
SavedRequestAwareAuthenticationSuccessHandler handler = new SavedRequestAwareAuthenticationSuccessHandler();
handler.setDefaultTargetUrl("/login.html");
return handler;
}
#Bean
public AuthenticationFailureHandler getFailureHandler(){
SimpleUrlAuthenticationFailureHandler handler = new SimpleUrlAuthenticationFailureHandler();
handler.setDefaultFailureUrl("/login.html");
return handler;
}
in your filter
#Autowired
#Qualifier("authenticationManager")
#Override
public void setAuthenticationManager(AuthenticationManager authenticationManager, AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) {
super.setAuthenticationManager(authenticationManager);
this.setAuthenticationSuccessHandler(successHandler);
this.setAuthenticationFailureHandler(failureHandler);
}
I made a custom filter and failureHandler. But to make it work i need to register handler in filter. So i willd be glad if someone will write how to do it in my code. I know that there are a lot of examples in stackowerflow but i'm new to spring and java and to understand how it works i need an example for my app. Please don't answer with "this is a duplicate".
My filter:
#Component("MyAuthFilter")
public class MyAuthFilter extends UsernamePasswordAuthenticationFilter {
private int errCode = 5;
#Autowired
#Qualifier("authenticationManager")
#Override
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
System.out.println("running my own version of UsernmePasswordFilter ... ");
String login = (String) request.getParameter("login");
String password = (String) request.getParameter("password");
errCode = validate(login, password);
System.out.println(login + " - " + password);
System.out.println(request.getQueryString());
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(login, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
private int validate(String login, String password) {
if (login.isEmpty() && password.isEmpty()) {
return 4;
}
if (login.isEmpty() && !password.isEmpty()) {
return 2;
}
if (!login.isEmpty() && password.isEmpty()) {
return 3;
}
return 1;
}
}
here is my handler:
public class LoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {
public LoginFailureHandler() {
System.out.println("i debug");
}
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
System.out.println("do smth");
super.onAuthenticationFailure(request, response, exception);
}
}
and my spring-security.xml:
<beans:bean id="authenticationFailureHandler" class="com.webproject.LoginFailureHandler" />
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/courses*" access="hasRole('ROLE_USER')" />
<custom-filter before="FORM_LOGIN_FILTER" ref="MyAuthFilter" />
<form-login
login-page="/login"
default-target-url="/courses"
username-parameter="loginField"
password-parameter="passwordField"
authentication-failure-handler-ref="authenticationFailureHandler"
/>
<csrf disabled="true" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="ars" password="1234" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Declare to beans and autowire them to your filter
#Bean
public AuthenticationFailureHandler getFailureHandler(){
SimpleUrlAuthenticationFailureHandler handler = new SimpleUrlAuthenticationFailureHandler();
handler.setDefaultFailureUrl("/login.html");
return handler;
}
MyAuthFilter
#Autowired
#Qualifier("authenticationManager")
#Override
public void setAuthenticationManager(AuthenticationManager authenticationManager, AuthenticationFailureHandler failureHandler) {
this.setAuthenticationManager(authenticationManager);
this.setAuthenticationFailureHandler(failureHandler);
}
I am working with spring-security 3.1 to implement two different logons. The first thing I have to a database that brings me CustomUserDetailService credentials datos.Este the same database is for administrator access. The second port is for the user but the information comes from a web service I call him with me a method validates the user. The problem I have with the second port, and to develop a CustomAuthenticationProvider for the second AuthenticationManager (web service), but when I try to access the spring-security user sends me to error page login.html? Error = true the furmulario administrator access. Esteb is my configuration file:
<http pattern="../resources/**" security="none" />
<http pattern="/login.html*" security="none" />
<http pattern="/loginUser.html*" security="none" />
<!-- USER -->
<http auto-config="true" authentication-manager-ref="wsAuthenticationManager" use-expressions="true" pattern="/testUser/**">
<intercept-url pattern="/loginUser.html" access="permitAll" />
<intercept-url pattern="/testUser/**" access="hasRole('user')" />
<access-denied-handler error-page="/403" />
<form-login login-page="/loginUser.html"
authentication-failure-url="/loginUser.html?login_error=true"
default-target-url="/testUser" />
<logout invalidate-session="true" logout-success-url="/logintUser.html" />
</http>
<beans:bean id="customAuthenticationProvider" class="net.universia.test.service.CustomAuthenticationProvider" />
<!-- Acceso contra WS -->
<authentication-manager id="wsAuthenticationManager">
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>
<!--ADMIN -->
<http auto-config="true" use-expressions="true" authentication-manager-ref="authenticationManager" >
<intercept-url pattern="/login.html" access="permitAll" />
<intercept-url pattern="/test/**" access="hasRole('admin')" />
<intercept-url pattern="/member/**" access="hasAnyRole('moderator','admin')" />
<intercept-url pattern="/testUser/**" access="hasRole('admin')" />
<access-denied-handler error-page="/403" />
<form-login login-page="/login.html"
authentication-failure-url="/login.html?login_error=true"
username-parameter="j_username" password-parameter="j_password"/>
<logout invalidate-session="true" logout-success-url="/loginUser.html" />
<remember-me user-service-ref="customUserDetailsService" />
</http>
<beans:bean id="customUserDetailsService" class="net.universia.test.service.CustomUserDetailsService" />
<beans:bean id="md5PasswordEncoder"
class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
<!-- Acceso contra base de datos -->
<authentication-manager alias="authenticationManager" id="authenticationManager">
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder hash="md5" />
</authentication-provider>
</authentication-manager>
</beans:beans>
CustomUserDetailService para administrator:
#Service
#Transactional(readOnly=true)
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private HibernateTestAdminDaoImpl userDAO;
public UserDetails loadUserByUsername(String login)throws UsernameNotFoundException {
TestAdmin userAdmin = null;
try {
userAdmin = userDAO.getTestAdmin(login);
} catch (BussinessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new User(
userAdmin.getLoginAdmin(),
userAdmin.getPasswordAdmin(),
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
getAuthorities(userAdmin.getRole().getIdRole())
);
}
public Collection<? extends GrantedAuthority> getAuthorities(Integer role) {
List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role));
return authList;
}
public List<String> getRoles(Integer role) {
List<String> roles = new ArrayList<String>();
if (role.intValue() == 1) {
roles.add("admin");
roles.add("moderator");
} else if (role.intValue() == 2) {
roles.add("moderator");
}
return roles;
}
public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
}
CustomAuthenticationProvider user:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private HibernateTestUsuarioDaoImpl userDAO;
UniversiaUser usw;
public CustomAuthenticationProvider() {
super();
}
// Retorna credenciales del usuario web service
public Authentication authenticate(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
/*
final String loginUser = authentication.getName();
final String password = authentication.getCredentials().toString();
try {
usw = userDAO.loginUserWS(loginUser, password);
} catch (UserRegistryWSException e) {
String errorCode = e.getLocalizedMessage();
System.out.print(errorCode);
} catch (Exception e) {
UsuarioUniversiaException ee = new UsuarioUniversiaException(
UsuarioUniversiaException.FERIA_VIRTUAL_USER_ERROR_LOGIN,
e);
ee.setLogin(loginUser);
throw ee;
}
if (usw.getEmail().equals("loginUser")) {
final List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("user"));
final UserDetails principal = new User(loginUser, password, grantedAuths);
final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
return auth;
} else {
return null;
}
*/
//Test parameters
final String loginUser = request.getParameter("username");
final String password = request.getParameter("password");
if (loginUser.equals("admin") && password.equals("system")) {
final List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("user"));
final UserDetails principal = new User(loginUser, password, grantedAuths);
final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
return auth;
} else {
return null;
}
}
#Override
public boolean supports(final Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// TODO Auto-generated method stub
return null;
}
}
In customautheticationprovider discuss what comes from the webservice and send test parameters
Thanks and any help is welcome
Now I have two running !!!
One customAuthenticationProvider user and customAuthenticationDetailService for Administrator and implement each filter
I work with Spring 3.1.1.
I have PAM authentication and I want to use spring security to denied users to access files.
Normally Configuration is
1. <http auto-config="true">
<intercept-url pattern="/test*" access="ROLE_USER" />
</http>
2. <authentication-manager>
<authentication-provider>
<user-service>
<user name="test" password="test" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
I do not want to use second section because I have MAP. I want to user first section.
Can I do this?
Can Anybody help me?
you need to define a custom authentication provider to set role(s) to users via checking PAM. for example, following code define a unix PAM authentication:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = String.valueOf(authentication.getPrincipal());
String password = String.valueOf(authentication.getCredentials());
PAM pam;
try {
pam = new PAM(pamServiceName);
} catch (PAMException e) {
throw new AuthenticationServiceException("Could not initialize PAM.", e);
}
try {
UnixUser user = pam.authenticate(username, password);
return new UsernamePasswordAuthenticationToken(user.getUserName(), authentication.getCredentials(), ROLE_USER);
} catch (PAMException e) {
throw new BadCredentialsException("PAM authentication failed.", e);
} finally {
pam.dispose();
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(
UsernamePasswordAuthenticationToken.class);
}
}
spring security configuration:
<authentication-manager>
<authentication-provider
ref="customAuthenticationProvider" />
</authentication-manager>
more example can be found from : https://www.javatips.net/api/org.springframework.security.authentication.badcredentialsexception
I'm trying to implement spring security 3.1.0.M1 and I'm unable to get my application to set the Authentication.getPrincipal to my custom UserDetails implementation. It always returns a principal of "guest" when I try to get the logged in user. See getLoggedInUser method below.
In Users.java (UserDetails impl) the getAuthorities method never gets called and maybe that's why the user_role doesn't get assigned.
to Maybe I've misconfigured something...I've attached 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;
}
Are you not getting compilation error on this line: auth.add("ROLE_USER");?
I think it should be : auth.add(new SimpleGrantedAuthority("ROLE_USER"));