/*
* 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.enums.UserReferer;
import com.rockagen.gnext.po.AuthUser;
import com.rockagen.gnext.service.AuthUserServ;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.Optional;
/**
* Authentication Handler
*
* @author ra
* @since JDK1.8
*/
public class ExAuthenticationHandler implements MessageSourceAware {
protected MessageSourceAccessor messages=SpringSecurityMessageSource.getAccessor();
/**
* HttpServletRequest Header params
*/
private String tokenName = "X-AUTH-TOKEN";
private String userReferer = "X-Referer";
private String username = "uid";
private int maxFailedAttempts = 6;
// 3 hours
private long lockedTime = 10800000;
private AuthUserServ authUserServ;
private ExTokenAuthentication exTokenAuthentication;
/**
* Authentication success handler
*
* @param request request
* @param response response
* @param authentication {@link org.springframework.security.core.Authentication}
*/
public void successHandler(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
String uid = authentication.getName();
successRegister(uid, request);
// Response Token
String token = exTokenAuthentication.newToken(uid);
if (CommUtil.isNotBlank(token)) {
response.setHeader(tokenName, token);
response.setStatus(HttpServletResponse.SC_OK);
} else {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
}
}
/**
* Success register
*
* @param uid uid
* @param request request
*/
private void successRegister(String uid, HttpServletRequest request) {
String currentIp = new ExWebAuthenticationDetails(request).getRemoteAddress();
Optional<AuthUser> user = authUserServ.load(uid);
user.ifPresent(x -> {
Date now = new Date();
x.setLastSignInAt(x.getCurrentSignInAt());
x.setCurrentSignInAt(now);
x.setLastSignInIp(x.getCurrentSignInIp());
x.setCurrentSignInIp(currentIp);
Integer signCount = Optional.ofNullable(x.getSignInCount()).orElse(0);
x.setSignInCount(++signCount);
x.setFailedAttempts(0);
// Referer
String referer = request.getHeader(userReferer);
x.setLastUserReferer(getReferer(referer));
authUserServ.add(x);
}
);
}
/**
* Authentication failure handler
*
* @param request request
* @param response response
*/
public void failureHandler(HttpServletRequest request, HttpServletResponse response) throws IOException {
String uid = request.getParameter(username);
try {
failureRegister(uid, request);
} catch (AuthenticationException e) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
}
}
/**
* Failure register
*
* @param uid uid
* @param request request
*/
private void failureRegister(String uid, HttpServletRequest request) {
String currentIp = new ExWebAuthenticationDetails(request).getRemoteAddress();
Optional<AuthUser> u = authUserServ.load(uid);
if (u.filter(AuthUser::enabled).isPresent()) {
AuthUser user = u.get();
Date date = new Date();
long now = date.getTime();
// Failed attempts count ++
Integer failedAttempts = user.getFailedAttempts();
if (failedAttempts == null) {
failedAttempts = 0;
}
user.setFailedAttempts(++failedAttempts);
user.setLastSignInAt(user.getCurrentSignInAt());
user.setCurrentSignInAt(date);
user.setLastSignInIp(user.getCurrentSignInIp());
user.setCurrentSignInIp(currentIp);
Integer signCount = user.getSignInCount();
if (signCount == null) {
signCount = 0;
}
user.setSignInCount(++signCount);
// Referer
String referer = request.getHeader(userReferer);
user.setLastUserReferer(getReferer(referer));
if(user.getLastSignInAt()!=null){
long lastTime = user.getLastSignInAt().getTime();
// auto lock
if (user.getFailedAttempts() >= maxFailedAttempts && (now - lastTime) <= lockedTime) {
// Locked user
user.setLockedAt(date);
user.setEnabled(0);
}
}
authUserServ.add(user);
// locked?
if (user.getEnabled() < 1) {
throw new DisabledException(messages.getMessage("AccountStatusUserDetailsChecker.locked"));
}
int onlyCount = maxFailedAttempts - user.getFailedAttempts();
throw new BadCredentialsException(messages.getMessage(
"AccountStatusUserDetailsChecker.onlyCount", new Object[]{onlyCount}));
} else {
throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
public UserReferer getReferer(String referer) {
UserReferer state = UserReferer.UNKNOWN;
try {
state = UserReferer.valueOf(referer);
} catch (Exception e) {
// DO NOT
}
return state;
}
public void setUserReferer(String userReferer) {
this.userReferer = userReferer;
}
public void setAuthUserServ(AuthUserServ authUserServ) {
this.authUserServ = authUserServ;
}
public void setTokenName(String tokenName) {
this.tokenName = tokenName;
}
public void setUsername(String username) {
this.username = username;
}
public void setMaxFailedAttempts(int maxFailedAttempts) {
this.maxFailedAttempts = maxFailedAttempts;
}
public void setLockedTime(long lockedTime) {
this.lockedTime = lockedTime;
}
public void setExTokenAuthentication(ExTokenAuthentication exTokenAuthentication) {
this.exTokenAuthentication = exTokenAuthentication;
}
@Override
public void setMessageSource(MessageSource messageSource) {
messages=new MessageSourceAccessor(messageSource);
}
}