/*
* Copyright 2014-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.rockagen.gnext.service.spring.security.extension;
import com.rockagen.commons.util.CommUtil;
import com.rockagen.gnext.po.AuthGroup;
import com.rockagen.gnext.po.AuthUser;
import com.rockagen.gnext.service.AuthUserServ;
import com.rockagen.gnext.tool.Crypto;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.*;
/**
* An {@link org.springframework.security.authentication.AuthenticationProvider} implementation that retrieves user details from a {@link org.springframework.security.core.userdetails.UserDetailsService}.
*
* @author ra
* @since JDK1.8
*/
public class ExAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
// 3 hours
private long lockedTime = 10800000;
private AuthUserServ authUserServ;
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
}
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
UserDetails loadedUser;
try {
loadedUser = loadUser(username, authentication.getCredentials().toString());
} catch (Exception repositoryProblem) {
throw new InternalAuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
}
return loadedUser;
}
/**
* Create a new {@link org.springframework.security.core.userdetails.UserDetails} by uid
*
* @param uid uid
* @param credentials Credentials(always was password)
* @return {@link org.springframework.security.core.userdetails.UserDetails}
* @throws org.springframework.security.authentication.BadCredentialsException if credentials invalid
*/
private UserDetails loadUser(String uid, String credentials) {
// Not empty
if(CommUtil.isBlank(uid) || CommUtil.isBlank(credentials)) {
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
// Load user
Optional<AuthUser> u=authUserServ.load(uid);
if(u.filter(x->x.enabled()).isPresent()){
AuthUser user=u.get();
// Check credentials
checkCredentials(user.getPassword(), credentials, user.getSalt());
// After authenticated handler
afterAuthenticatedHandler(user);
List<GrantedAuthority> authorities = new LinkedList<>();
Set<AuthGroup> groups = user.getGroups();
if (groups != null && groups.size() > 0) {
groups.forEach(x -> x.getRoles().forEach(y -> authorities.add(new SimpleGrantedAuthority(y.getName().trim()))));
}
return new User(user.getUid(), user.getPassword(), true, true, true, true, authorities);
}else{
throw new UsernameNotFoundException(messages.getMessage("",
new Object[]{uid}, "User {0} has no GrantedAuthority"));
}
}
/**
* Check password is valid?
*
* @param encPass - a pre-encoded password
* @param credentials Credentials(always was password)
* @param salt - a salt value.
* @throws org.springframework.security.authentication.BadCredentialsException if credentials invalid
*/
protected void checkCredentials(String encPass, String credentials, String salt) {
if (!Crypto.passwdValid(encPass, credentials, salt)) {
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
/**
* Do something after authenticated
*
* @param user {@link org.newland.kserv.po.AuthUser}
*/
protected void afterAuthenticatedHandler(AuthUser user) {
// CASE 1: Auto unlocked
if (!user.enabled()) {
Date date = new Date();
long now = date.getTime();
if(user.getLastSignInAt()!=null){
long lastTime = user.getLastSignInAt().getTime();
if (now - lastTime > lockedTime) {
// Unlocked user
user.setEnabledAt(date);
user.setEnabled(1);
}
}
}
// CASE 2: ..
}
public void setAuthUserServ(AuthUserServ authUserServ) {
this.authUserServ = authUserServ;
}
/**
* Locked user times
*
* @param lockedTime locked time
*/
public void setLockedTime(long lockedTime) {
this.lockedTime = lockedTime;
}
}