Spring Security and PAM - java

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

Related

Spring security shows "bad credentials" error instead of redirect

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);
}

How to refer brcypt encoder to customized authentication provider?

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/

Spring Security 2 Custom Authentication Provider not saving security context

I've changed the default Authentication Provider for a Custom one.
This is my AuthenticationProvider
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private ParamsProperties paramsProperties;
#SuppressWarnings("unchecked")
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//Check username and passwd
String user = (String) authentication.getPrincipal();
String pass = (String) authentication.getCredentials();
if(StringUtils.isBlank(user) || StringUtils.isBlank(pass) ){
throw new BadCredentialsException("Incorrect username/password");
}
//Create SSO
SingleSignOnService service = new SingleSignOnService(paramsProperties.getServicesServer());
try {
//Check logged
service.setUsername(authentication.getName());
service.setPassword(authentication.getCredentials().toString());
ClientResponse response = service.call();
String result = response.getEntity(String.class);
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> map = mapper.readValue(result, new TypeReference<Map<String,Object>>() {} );
//Read code
String code = (String)map.get("code");
log.debug(" ** [Authenticate] Result: " + code );
for (String s : (List<String>)map.get( "messages" ) ) {
log.debug(" [Authenticate] Message: " + s );
}
if ( code.equals( "SESSION_CREATED" ) || code.equals( "SESSION_UPDATED" ) || code.equals( "SESSION_VERIFIED" ) ) {
UsernamePasswordAuthenticationToken tokenSSO = LoginHelper.getuserSringTokenFromAuthService(map);
return tokenSSO;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
throw new AuthenticationServiceException( e.getMessage() );
}
}
public boolean supports(Class authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
And this is my security.xml
<http>
<form-login default-target-url ="/Login.html" always-use-default-target="true" login-page="/Login.html" login-processing-url="/j_spring_security_check"
authentication-failure-url="/Login.html" />
<http-basic />
<logout logout-success-url="/Login.html" />
</http>
<beans:bean id="localeFilter" class="com.mycomp.comunes.server.spring.controller.login.MyLocaleFilter" lazy-init="true">
<custom-filter position="LAST"/>
</beans:bean>
<beans:bean id="authenticationProvider" class="com.indra.rfef.comunes.server.spring.manager.autenticacion.CustomAuthenticationProvider">
<custom-authentication-provider />
</beans:bean>
It gets over my CustomAuthenticationProvider, and authenticates correctly the user. But when returning tokenSSO, of type UsernamePasswordAuthenticationToken, it seems it's not saving the user on the Security Context, and when I redirect the user (on the callback of the authenticate) to the index.html, I get redirected back to Login.html.
Why could this happen? I'm I forgetting something?
Please fix your configuration:
<http>
<intercept-url pattern="/Login*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/**" access="ROLE_USER"/>
<form-login login-page="/Login.html" login-processing-url="/j_spring_security_check" authentication-failure-url="/Login.html" />
<http-basic />
<logout logout-success-url="/Login.html" />
</http>
Remove default-target-url ="/Login.html". It makes the redirection after login to the same login page. The default is /.
Add security on all URLs <intercept-url pattern="/**" access="ROLE_USER"/>
Do not remove the anonymous access from the login page
Why you need BasicAuthentication? Remove it if not required: <http-basic />

Ldap configuration in Spring Security - own class

I want to write my own LDAP authentication provider. I am extending AbstractUserDetailsAuthenticationProvider, which has a method retrieveUser(String username, UsernamePasswordAuthenticationToken authentication).
I want to override this method and write my own data retrieving method. How to do that in Java? How to make an LDAP query and how connect to the LDAP server? I was searching in Internet but I didn't find anything that helped.
EDIT: 22.01.2013
#Override
protected UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
LdapUser userDetail = null;
log.entry("retrieveUser", authentication.getPrincipal());
UsernamePasswordAuthenticationToken userToken = authentication;
String userName = userToken.getName();
userName = userName != null ? userName.toLowerCase() : userName;
String password = userToken.getCredentials().toString();
try {
if (password == null || "".equals(password)) {
log.debug("retrieveUser", "no password provided");
throw new AuthenticationCredentialsNotFoundException(
"Invalid login or password");
}
}
catch (AuthenticationCredentialsNotFoundException e) {
log.debug("retrieveUser", "no password provided");
}
// connection with ldap and check retrieved username and password
connect = connection(userName, password);
if (connect) {
log.debug("retrieve user", "correct connection with ldap");
userDetail = new LdapUser();
setUserDetails(userDetail, ctx, username);
} else {
log.error("retrieve user", "Failed connection");
}
log.exit("retrieveUser", "user logged: " + userDetail);
return userDetail;
}
My security.xml file
<http auto-config='true'>
<intercept-url pattern="/**/*.ico" filters="none" />
<intercept-url pattern="/**/*.gif" filters="none" />
<intercept-url pattern="/**/*.jpg" filters="none" />
<intercept-url pattern="/**/*.css" filters="none" />
<intercept-url pattern="/**/*.js" filters="none" />
<intercept-url pattern="/**/*.png" filters="none" />
<intercept-url pattern="/logout.jsp*" filters="none" />
<intercept-url pattern="/index.jsp*" filters="none" />
<intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN" />
<logout logout-success-url="/index.jsp"/>
<form-login login-page="/index.jsp"
authentication-failure-url="/error_ldap.jsp"
default-target-url="/main_ldap.jsp" always-use-default-target="true" />
</http>
<authentication-manager>
<authentication-provider ref="ldapAuthenticationProvider">
<password-encoder hash="sha" />
</authentication-provider>
</authentication-manager>
When login is suceed I got redirect to main_ldap.jsp, but if authentication fail, I got this error. I tried to throw exception UsernameNotFoundException instead returning null in retrieveUser method (which is not allowed) but anything happend (only i got this exception).
You can connect to LDAP from java:
http://docs.oracle.com/javase/jndi/tutorial/ldap/security/ldap.html
but spring security already has ldap integration, you can use of the methods described here:
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ldap.html
...
xml config for using your own UserDetails service is:
<b:bean id="userDetailsService" class="your.class.here">
</b:bean>
<authentication-provider user-service-ref="userDetailsService">
</authentication-provider>

Spring Security returning guest instead of UserDetails for Authentication.getPrincipal()

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"));

Categories

Resources