mirror of
https://gitee.com/dromara/MaxKey.git
synced 2026-05-14 20:50:14 +08:00
separate common
This commit is contained in:
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.maxkey.authn.online.OnlineTicketServices;
|
||||
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
|
||||
import org.maxkey.authn.support.rememberme.AbstractRemeberMeService;
|
||||
import org.maxkey.configuration.ApplicationConfig;
|
||||
import org.maxkey.constants.ConstantsLoginType;
|
||||
import org.maxkey.crypto.password.PasswordReciprocal;
|
||||
import org.maxkey.crypto.password.otp.AbstractOtpAuthn;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.web.WebConstants;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
/**
|
||||
* login Authentication abstract class.
|
||||
*
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractAuthenticationProvider {
|
||||
private static final Logger _logger =
|
||||
LoggerFactory.getLogger(AbstractAuthenticationProvider.class);
|
||||
|
||||
@Autowired
|
||||
@Qualifier("applicationConfig")
|
||||
protected ApplicationConfig applicationConfig;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("authenticationRealm")
|
||||
protected AbstractAuthenticationRealm authenticationRealm;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("tfaOptAuthn")
|
||||
protected AbstractOtpAuthn tfaOptAuthn;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("remeberMeService")
|
||||
protected AbstractRemeberMeService remeberMeService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("onlineTicketServices")
|
||||
protected OnlineTicketServices onlineTicketServices;
|
||||
|
||||
public static ArrayList<GrantedAuthority> grantedAdministratorsAuthoritys = new ArrayList<GrantedAuthority>();
|
||||
|
||||
static {
|
||||
grantedAdministratorsAuthoritys.add(new SimpleGrantedAuthority("ROLE_ADMINISTRATORS"));
|
||||
}
|
||||
|
||||
protected abstract String getProviderName();
|
||||
|
||||
protected abstract Authentication doInternalAuthenticate(LoginCredential authentication);
|
||||
|
||||
public abstract Authentication basicAuthenticate(LoginCredential authentication) ;
|
||||
|
||||
public abstract Authentication trustAuthentication(
|
||||
String username,
|
||||
String type,
|
||||
String provider,
|
||||
String code,
|
||||
String message);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public boolean supports(Class authentication) {
|
||||
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
|
||||
}
|
||||
|
||||
/**
|
||||
* authenticate .
|
||||
*
|
||||
*/
|
||||
public Authentication authenticate(LoginCredential loginCredential)
|
||||
throws AuthenticationException {
|
||||
_logger.debug("Trying to authenticate user '{}' via {}",
|
||||
loginCredential.getPrincipal(), getProviderName());
|
||||
// 登录SESSION
|
||||
_logger.debug("Login Session {}.", WebContext.getSession().getId());
|
||||
Authentication authentication = null;
|
||||
try {
|
||||
authentication = doInternalAuthenticate(loginCredential);
|
||||
} catch (AuthenticationException e) {
|
||||
_logger.error("Failed to authenticate user {} via {}: {}",
|
||||
new Object[] { loginCredential.getPrincipal(),
|
||||
getProviderName(),
|
||||
e.getMessage() });
|
||||
WebContext.setAttribute(
|
||||
WebConstants.LOGIN_ERROR_SESSION_MESSAGE, e.getMessage());
|
||||
} catch (Exception e) {
|
||||
String message = "Unexpected exception in " + getProviderName() + " authentication:";
|
||||
_logger.error("Login error " + message, e);
|
||||
}
|
||||
|
||||
if (authentication== null || !authentication.isAuthenticated()) {
|
||||
return authentication;
|
||||
}
|
||||
|
||||
// user authenticated
|
||||
_logger.debug("'{}' authenticated successfully by {}.",
|
||||
authentication.getPrincipal(), getProviderName());
|
||||
|
||||
changeSession(authentication);
|
||||
|
||||
authenticationRealm.insertLoginHistory(
|
||||
WebContext.getUserInfo(), ConstantsLoginType.LOCAL, "", "xe00000004", "success");
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
protected void changeSession(Authentication authentication) {
|
||||
|
||||
HashMap<String,Object> sessionAttributeMap = new HashMap<String,Object>();
|
||||
for(String attributeName : WebContext.sessionAttributeNameList) {
|
||||
sessionAttributeMap.put(attributeName, WebContext.getAttribute(attributeName));
|
||||
}
|
||||
|
||||
//new Session
|
||||
WebContext.getSession().invalidate();
|
||||
|
||||
for(String attributeName : WebContext.sessionAttributeNameList) {
|
||||
WebContext.setAttribute(attributeName, sessionAttributeMap.get(attributeName));
|
||||
}
|
||||
|
||||
WebContext.setAttribute(
|
||||
WebConstants.CURRENT_USER_SESSION_ID, WebContext.getSession().getId());
|
||||
_logger.debug("Login Success Session {}.", WebContext.getSession().getId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* session validate.
|
||||
*
|
||||
* @param sessionId String
|
||||
*/
|
||||
protected void sessionValid(String sessionId) {
|
||||
if (sessionId == null || !sessionId.equals(WebContext.getSession().getId())) {
|
||||
_logger.debug("login session valid error.");
|
||||
_logger.debug("login session sessionId " + sessionId);
|
||||
_logger.debug("login getSession sessionId " + WebContext.getSession().getId());
|
||||
|
||||
String message = WebContext.getI18nValue("login.error.session");
|
||||
throw new BadCredentialsException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session validate.
|
||||
*
|
||||
* @param jwtToken String
|
||||
*/
|
||||
protected void jwtTokenValid(String jwtToken) {
|
||||
/*
|
||||
* if(jwtToken!=null && ! jwtToken.equals("")){
|
||||
* if(jwtLoginService.jwtTokenValidation(j_jwtToken)){ return; } }
|
||||
*/
|
||||
String message = WebContext.getI18nValue("login.error.session");
|
||||
_logger.debug("login session valid error.");
|
||||
throw new BadCredentialsException(message);
|
||||
}
|
||||
|
||||
protected void authTypeValid(String authType) {
|
||||
_logger.debug("Login AuthN Type " + authType);
|
||||
if (authType != null && (
|
||||
authType.equalsIgnoreCase("basic")
|
||||
|| authType.equalsIgnoreCase("tfa"))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String message = WebContext.getI18nValue("login.error.authtype");
|
||||
_logger.debug("Login AuthN type must eq basic or tfa , Error message is " + message);
|
||||
throw new BadCredentialsException(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* captcha validate .
|
||||
*
|
||||
* @param authType String
|
||||
* @param captcha String
|
||||
*/
|
||||
protected void captchaValid(String captcha, String authType) {
|
||||
// for basic
|
||||
if (applicationConfig.getLoginConfig().isCaptcha() && authType.equalsIgnoreCase("basic")) {
|
||||
_logger.info("captcha : "
|
||||
+ WebContext.getSession().getAttribute(
|
||||
WebConstants.KAPTCHA_SESSION_KEY).toString());
|
||||
if (captcha == null || !captcha
|
||||
.equals(WebContext.getSession().getAttribute(
|
||||
WebConstants.KAPTCHA_SESSION_KEY).toString())) {
|
||||
String message = WebContext.getI18nValue("login.error.captcha");
|
||||
_logger.debug("login captcha valid error.");
|
||||
throw new BadCredentialsException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* captcha validate.
|
||||
*
|
||||
* @param otpCaptcha String
|
||||
* @param authType String
|
||||
* @param userInfo UserInfo
|
||||
*/
|
||||
protected void tftcaptchaValid(String otpCaptcha, String authType, UserInfo userInfo) {
|
||||
// for one time password 2 factor
|
||||
if (applicationConfig.getLoginConfig().isMfa() && authType.equalsIgnoreCase("tfa")) {
|
||||
UserInfo validUserInfo = new UserInfo();
|
||||
validUserInfo.setUsername(userInfo.getUsername());
|
||||
String sharedSecret =
|
||||
PasswordReciprocal.getInstance().decoder(userInfo.getSharedSecret());
|
||||
validUserInfo.setSharedSecret(sharedSecret);
|
||||
validUserInfo.setSharedCounter(userInfo.getSharedCounter());
|
||||
validUserInfo.setId(userInfo.getId());
|
||||
if (otpCaptcha == null || !tfaOptAuthn.validate(validUserInfo, otpCaptcha)) {
|
||||
String message = WebContext.getI18nValue("login.error.captcha");
|
||||
_logger.debug("login captcha valid error.");
|
||||
throw new BadCredentialsException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* login user by j_username and j_cname first query user by j_cname if first
|
||||
* step userinfo is null,query user from system.
|
||||
*
|
||||
* @param username String
|
||||
* @param password String
|
||||
* @return
|
||||
*/
|
||||
public UserInfo loadUserInfo(String username, String password) {
|
||||
UserInfo userInfo = authenticationRealm.loadUserInfo(username, password);
|
||||
|
||||
if (userInfo != null) {
|
||||
if (userInfo.getUserType() == "SYSTEM") {
|
||||
_logger.debug("SYSTEM User Login. ");
|
||||
} else {
|
||||
_logger.debug("User Login. ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* check input password empty.
|
||||
*
|
||||
* @param password String
|
||||
* @return
|
||||
*/
|
||||
protected boolean emptyPasswordValid(String password) {
|
||||
if (null == password || "".equals(password)) {
|
||||
throw new BadCredentialsException(WebContext.getI18nValue("login.error.password.null"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* check input username or password empty.
|
||||
*
|
||||
* @param email String
|
||||
* @return
|
||||
*/
|
||||
protected boolean emptyEmailValid(String email) {
|
||||
if (null == email || "".equals(email)) {
|
||||
throw new BadCredentialsException("login.error.email.null");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* check input username empty.
|
||||
*
|
||||
* @param username String
|
||||
* @return
|
||||
*/
|
||||
protected boolean emptyUsernameValid(String username) {
|
||||
if (null == username || "".equals(username)) {
|
||||
throw new BadCredentialsException(WebContext.getI18nValue("login.error.username.null"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean userinfoValid(UserInfo userInfo, String username) {
|
||||
if (null == userInfo) {
|
||||
String message = WebContext.getI18nValue("login.error.username");
|
||||
_logger.debug("login user " + username + " not in this System ." + message);
|
||||
UserInfo loginUser = new UserInfo(username);
|
||||
loginUser.setId(loginUser.generateId());
|
||||
loginUser.setDisplayName("not exist");
|
||||
loginUser.setLoginCount(0);
|
||||
authenticationRealm.insertLoginHistory(loginUser, ConstantsLoginType.LOCAL, "",
|
||||
WebContext.getI18nValue("login.error.username"), "user not exist");
|
||||
throw new BadCredentialsException(WebContext.getI18nValue("login.error.username"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setApplicationConfig(ApplicationConfig applicationConfig) {
|
||||
this.applicationConfig = applicationConfig;
|
||||
}
|
||||
|
||||
public void setAuthenticationRealm(AbstractAuthenticationRealm authenticationRealm) {
|
||||
this.authenticationRealm = authenticationRealm;
|
||||
}
|
||||
|
||||
public void setTfaOptAuthn(AbstractOtpAuthn tfaOptAuthn) {
|
||||
this.tfaOptAuthn = tfaOptAuthn;
|
||||
}
|
||||
|
||||
public void setRemeberMeService(AbstractRemeberMeService remeberMeService) {
|
||||
this.remeberMeService = remeberMeService;
|
||||
}
|
||||
|
||||
public void setOnlineTicketServices(OnlineTicketServices onlineTicketServices) {
|
||||
this.onlineTicketServices = onlineTicketServices;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
public class LoginCredential implements Authentication {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 3125709257481600320L;
|
||||
String username;
|
||||
String password;
|
||||
String sessionId;
|
||||
String captcha;
|
||||
String otpCaptcha;
|
||||
String remeberMe;
|
||||
String authType;
|
||||
String jwtToken;
|
||||
String onlineTicket;
|
||||
ArrayList<GrantedAuthority> grantedAuthority;
|
||||
boolean authenticated;
|
||||
boolean roleAdministrators;
|
||||
|
||||
/**
|
||||
* BasicAuthentication.
|
||||
*/
|
||||
public LoginCredential() {
|
||||
}
|
||||
|
||||
/**
|
||||
* BasicAuthentication.
|
||||
*/
|
||||
public LoginCredential(String username,String password,String authType) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.authType = authType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Login Credential";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return grantedAuthority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return this.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDetails() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticated() {
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
|
||||
this.authenticated = authenticated;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(String sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
public String getCaptcha() {
|
||||
return captcha;
|
||||
}
|
||||
|
||||
public void setCaptcha(String captcha) {
|
||||
this.captcha = captcha;
|
||||
}
|
||||
|
||||
public String getOtpCaptcha() {
|
||||
return otpCaptcha;
|
||||
}
|
||||
|
||||
public void setOtpCaptcha(String otpCaptcha) {
|
||||
this.otpCaptcha = otpCaptcha;
|
||||
}
|
||||
|
||||
public String getRemeberMe() {
|
||||
return remeberMe;
|
||||
}
|
||||
|
||||
public void setRemeberMe(String remeberMe) {
|
||||
this.remeberMe = remeberMe;
|
||||
}
|
||||
|
||||
public String getAuthType() {
|
||||
return authType;
|
||||
}
|
||||
|
||||
public void setAuthType(String authType) {
|
||||
this.authType = authType;
|
||||
}
|
||||
|
||||
public String getJwtToken() {
|
||||
return jwtToken;
|
||||
}
|
||||
|
||||
public void setJwtToken(String jwtToken) {
|
||||
this.jwtToken = jwtToken;
|
||||
}
|
||||
|
||||
public ArrayList<GrantedAuthority> getGrantedAuthority() {
|
||||
return grantedAuthority;
|
||||
}
|
||||
|
||||
public void setGrantedAuthority(ArrayList<GrantedAuthority> grantedAuthority) {
|
||||
this.grantedAuthority = grantedAuthority;
|
||||
}
|
||||
|
||||
public String getOnlineTicket() {
|
||||
return onlineTicket;
|
||||
}
|
||||
|
||||
public void setOnlineTicket(String onlineTicket) {
|
||||
this.onlineTicket = onlineTicket;
|
||||
}
|
||||
|
||||
public boolean isRoleAdministrators() {
|
||||
return roleAdministrators;
|
||||
}
|
||||
|
||||
public void setRoleAdministrators(boolean roleAdministrators) {
|
||||
this.roleAdministrators = roleAdministrators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("BasicAuthentication [username=").append(username)
|
||||
.append(", password=").append(password)
|
||||
.append(", sessionId=").append(sessionId)
|
||||
.append(", captcha=").append(captcha)
|
||||
.append(", otpCaptcha=").append(otpCaptcha)
|
||||
.append(", remeberMe=").append(remeberMe)
|
||||
.append(", authType=").append(authType)
|
||||
.append(", jwtToken=").append(jwtToken)
|
||||
.append(", grantedAuthority=").append(grantedAuthority)
|
||||
.append(", authenticated=").append(authenticated)
|
||||
.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.maxkey.authn.online.OnlineTicket;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.web.WebConstants;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
|
||||
/**
|
||||
* database Authentication provider.
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class RealmAuthenticationProvider extends AbstractAuthenticationProvider {
|
||||
private static final Logger _logger =
|
||||
LoggerFactory.getLogger(RealmAuthenticationProvider.class);
|
||||
|
||||
protected String getProviderName() {
|
||||
return "RealmAuthenticationProvider";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Authentication doInternalAuthenticate(LoginCredential loginCredential) {
|
||||
|
||||
_logger.debug("authentication " + loginCredential);
|
||||
|
||||
sessionValid(loginCredential.getSessionId());
|
||||
|
||||
//jwtTokenValid(j_jwtToken);
|
||||
|
||||
authTypeValid(loginCredential.getAuthType());
|
||||
|
||||
captchaValid(loginCredential.getCaptcha(),loginCredential.getAuthType());
|
||||
|
||||
emptyPasswordValid(loginCredential.getPassword());
|
||||
|
||||
UserInfo userInfo = null;
|
||||
|
||||
emptyUsernameValid(loginCredential.getUsername());
|
||||
|
||||
userInfo = loadUserInfo(loginCredential.getUsername(),loginCredential.getPassword());
|
||||
|
||||
userinfoValid(userInfo, loginCredential.getPassword());
|
||||
|
||||
tftcaptchaValid(loginCredential.getOtpCaptcha(),loginCredential.getAuthType(),userInfo);
|
||||
|
||||
authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(userInfo);
|
||||
|
||||
authenticationRealm.passwordMatches(userInfo, loginCredential.getPassword());
|
||||
|
||||
UsernamePasswordAuthenticationToken authenticationToken = setOnline(loginCredential,userInfo);
|
||||
//RemeberMe Config check then set RemeberMe cookies
|
||||
if (applicationConfig.getLoginConfig().isRemeberMe()) {
|
||||
if (loginCredential.getRemeberMe() != null && loginCredential.getRemeberMe().equals("remeberMe")) {
|
||||
WebContext.getSession().setAttribute(
|
||||
WebConstants.REMEBER_ME_SESSION,loginCredential.getUsername());
|
||||
_logger.debug("do Remeber Me");
|
||||
remeberMeService.createRemeberMe(
|
||||
userInfo.getUsername(),
|
||||
WebContext.getRequest(),
|
||||
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes())
|
||||
.getResponse()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication basicAuthenticate(LoginCredential loginCredential) {
|
||||
UserInfo loadeduserInfo = loadUserInfo(loginCredential.getUsername(), "");
|
||||
if (loadeduserInfo != null) {
|
||||
authenticationRealm.passwordMatches(loadeduserInfo, loginCredential.getPassword());
|
||||
|
||||
authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(loadeduserInfo);
|
||||
|
||||
authenticationRealm.insertLoginHistory(loadeduserInfo, loginCredential.getAuthType(), "", "", "SUCCESS");
|
||||
|
||||
return setOnline(loginCredential,loadeduserInfo);
|
||||
}else {
|
||||
String message = WebContext.getI18nValue("login.error.username");
|
||||
_logger.debug("login user " + loginCredential.getUsername() + " not in this System ." + message);
|
||||
throw new BadCredentialsException(WebContext.getI18nValue("login.error.username"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* trustAuthentication.
|
||||
* @param username String
|
||||
* @param type String
|
||||
* @param provider String
|
||||
* @param code String
|
||||
* @param message String
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public Authentication trustAuthentication(String username,
|
||||
String type,
|
||||
String provider,
|
||||
String code,
|
||||
String message) {
|
||||
UserInfo loadeduserInfo = loadUserInfo(username, "");
|
||||
if (loadeduserInfo != null) {
|
||||
LoginCredential loginCredential = new LoginCredential();
|
||||
loginCredential.setUsername(loadeduserInfo.getUsername());
|
||||
|
||||
authenticationRealm.insertLoginHistory(loadeduserInfo, type, provider, code, message);
|
||||
|
||||
return setOnline(loginCredential,loadeduserInfo);
|
||||
}else {
|
||||
String i18nMessage = WebContext.getI18nValue("login.error.username");
|
||||
_logger.debug("login user " + username + " not in this System ." + i18nMessage);
|
||||
throw new BadCredentialsException(WebContext.getI18nValue("login.error.username"));
|
||||
}
|
||||
}
|
||||
|
||||
public UsernamePasswordAuthenticationToken setOnline(LoginCredential credential,UserInfo userInfo) {
|
||||
//Online Tickit Id
|
||||
String onlineTickitId = WebConstants.ONLINE_TICKET_PREFIX + "-" + java.util.UUID.randomUUID().toString().toLowerCase();
|
||||
_logger.debug("set online Tickit Cookie " + onlineTickitId + " on domain "+ this.applicationConfig.getBaseDomainName());
|
||||
|
||||
OnlineTicket onlineTicket = new OnlineTicket(onlineTickitId);
|
||||
|
||||
//set ONLINE_TICKET cookie
|
||||
WebContext.setCookie(WebContext.getResponse(),
|
||||
this.applicationConfig.getBaseDomainName(),
|
||||
WebConstants.ONLINE_TICKET_NAME,
|
||||
onlineTickitId);
|
||||
|
||||
SigninPrincipal signinPrincipal = new SigninPrincipal(userInfo);
|
||||
//set OnlineTicket
|
||||
signinPrincipal.setOnlineTicket(onlineTicket);
|
||||
ArrayList<GrantedAuthority> grantedAuthoritys = authenticationRealm.grantAuthority(userInfo);
|
||||
signinPrincipal.setAuthenticated(true);
|
||||
|
||||
for(GrantedAuthority administratorsAuthority : grantedAdministratorsAuthoritys) {
|
||||
if(grantedAuthoritys.contains(administratorsAuthority)) {
|
||||
signinPrincipal.setRoleAdministrators(true);
|
||||
_logger.trace("ROLE ADMINISTRATORS Authentication .");
|
||||
}
|
||||
}
|
||||
_logger.debug("Granted Authority " + grantedAuthoritys);
|
||||
|
||||
signinPrincipal.setGrantedAuthorityApps(authenticationRealm.queryAuthorizedApps(grantedAuthoritys));
|
||||
|
||||
UsernamePasswordAuthenticationToken authenticationToken =
|
||||
new UsernamePasswordAuthenticationToken(
|
||||
signinPrincipal,
|
||||
"PASSWORD",
|
||||
grantedAuthoritys
|
||||
);
|
||||
|
||||
authenticationToken.setDetails(
|
||||
new WebAuthenticationDetails(WebContext.getRequest()));
|
||||
|
||||
onlineTicket.setAuthentication(authenticationToken);
|
||||
|
||||
this.onlineTicketServices.store(onlineTickitId, onlineTicket);
|
||||
|
||||
/*
|
||||
* put userInfo to current session context
|
||||
*/
|
||||
WebContext.setAuthentication(authenticationToken);
|
||||
|
||||
WebContext.setUserInfo(userInfo);
|
||||
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.maxkey.authn.support.rememberme.AbstractRemeberMeService;
|
||||
import org.maxkey.web.WebConstants;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* An authentication success strategy which can make use of the
|
||||
* {@link DefaultSavedRequest} which may have been stored in the session by the
|
||||
* {@link ExceptionTranslationFilter}. When such a request is intercepted and
|
||||
* requires authentication, the request data is stored to record the original
|
||||
* destination before the authentication process commenced, and to allow the
|
||||
* request to be reconstructed when a redirect to the same URL occurs. This
|
||||
* class is responsible for performing the redirect to the original URL if
|
||||
* appropriate.
|
||||
* <p>
|
||||
* Following a successful authentication, it decides on the redirect
|
||||
* destination, based on the following scenarios:
|
||||
* <ul>
|
||||
* <li>If the {@code alwaysUseDefaultTargetUrl} property is set to true, the
|
||||
* {@code defaultTargetUrl} will be used for the destination. Any
|
||||
* {@code DefaultSavedRequest} stored in the session will be removed.</li>
|
||||
* <li>If the {@code targetUrlParameter} has been set on the request, the value
|
||||
* will be used as the destination. Any {@code DefaultSavedRequest} will again
|
||||
* be removed.</li>
|
||||
* <li>If a {@link SavedRequest} is found in the {@code RequestCache} (as set by
|
||||
* the {@link ExceptionTranslationFilter} to record the original destination
|
||||
* before the authentication process commenced), a redirect will be performed to
|
||||
* the Url of that original destination. The {@code SavedRequest} object will
|
||||
* remain cached and be picked up when the redirected request is received (See
|
||||
* {@link org.springframework.security.web.savedrequest.SavedRequestAwareWrapper
|
||||
* SavedRequestAwareWrapper}).</li>
|
||||
* <li>If no {@code SavedRequest} is found, it will delegate to the base class.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public class SavedRequestAwareAuthenticationSuccessHandler
|
||||
extends SimpleUrlAuthenticationSuccessHandler {
|
||||
protected final Logger _logger = LoggerFactory.getLogger(
|
||||
SavedRequestAwareAuthenticationSuccessHandler.class);
|
||||
|
||||
@Autowired
|
||||
@Qualifier("remeberMeService")
|
||||
protected AbstractRemeberMeService remeberMeService;
|
||||
|
||||
private RequestCache requestCache = new HttpSessionRequestCache();
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws ServletException, IOException {
|
||||
SavedRequest savedRequest = requestCache.getRequest(request, response);
|
||||
|
||||
remeberMeService.createRemeberMe(
|
||||
authentication.getPrincipal().toString(), request, response);
|
||||
|
||||
if (savedRequest == null) {
|
||||
super.onAuthenticationSuccess(request, response, authentication);
|
||||
|
||||
return;
|
||||
}
|
||||
String targetUrlParameter = getTargetUrlParameter();
|
||||
if (isAlwaysUseDefaultTargetUrl()
|
||||
|| (targetUrlParameter != null
|
||||
&& StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
|
||||
requestCache.removeRequest(request, response);
|
||||
super.onAuthenticationSuccess(request, response, authentication);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
clearAuthenticationAttributes(request);
|
||||
|
||||
// Use the DefaultSavedRequest URL
|
||||
String targetUrl = savedRequest.getRedirectUrl();
|
||||
|
||||
// is cas login , with service parameter
|
||||
logger.info("CAS " + request.getParameter(WebConstants.CAS_SERVICE_PARAMETER));
|
||||
if (request.getParameter(WebConstants.CAS_SERVICE_PARAMETER) != null
|
||||
&& request.getParameter(WebConstants.CAS_SERVICE_PARAMETER).startsWith("http")) {
|
||||
targetUrl = WebContext.getHttpContextPath() + "/authorize/cas/login?service="
|
||||
+ request.getParameter(WebConstants.CAS_SERVICE_PARAMETER);
|
||||
}
|
||||
targetUrl = targetUrl == null ? "/forwardindex" : targetUrl;
|
||||
logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);
|
||||
getRedirectStrategy().sendRedirect(request, response, targetUrl);
|
||||
}
|
||||
|
||||
public void setRequestCache(RequestCache requestCache) {
|
||||
this.requestCache = requestCache;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.maxkey.authn.online.OnlineTicket;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
|
||||
public class SigninPrincipal implements UserDetails {
|
||||
private static final long serialVersionUID = -110742975439268030L;
|
||||
UserInfo userInfo;
|
||||
|
||||
UserDetails userDetails;
|
||||
|
||||
OnlineTicket onlineTicket;
|
||||
ArrayList<GrantedAuthority> grantedAuthority;
|
||||
ArrayList<GrantedAuthority> grantedAuthorityApps;
|
||||
boolean authenticated;
|
||||
boolean roleAdministrators;
|
||||
|
||||
private boolean accountNonExpired;
|
||||
|
||||
private boolean accountNonLocked;
|
||||
|
||||
private boolean credentialsNonExpired;
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
/**
|
||||
* SigninPrincipal.
|
||||
*/
|
||||
public SigninPrincipal() {
|
||||
}
|
||||
|
||||
/**
|
||||
* SigninPrincipal.
|
||||
*/
|
||||
public SigninPrincipal(UserInfo userInfo) {
|
||||
this.userInfo = userInfo;
|
||||
this.authenticated = true;
|
||||
this.accountNonExpired = true;
|
||||
this.accountNonLocked = true;
|
||||
this.credentialsNonExpired =true;
|
||||
this.enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* SigninPrincipal.
|
||||
*/
|
||||
public SigninPrincipal(UserDetails userDetails) {
|
||||
this.userDetails = userDetails;
|
||||
this.authenticated = true;
|
||||
}
|
||||
|
||||
public UserInfo getUserInfo() {
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
public void setUserInfo(UserInfo userInfo) {
|
||||
this.userInfo = userInfo;
|
||||
}
|
||||
|
||||
public boolean isAuthenticated() {
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
public void setAuthenticated(boolean authenticated) {
|
||||
this.authenticated = authenticated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return grantedAuthority;
|
||||
}
|
||||
|
||||
public ArrayList<GrantedAuthority> getGrantedAuthority() {
|
||||
return grantedAuthority;
|
||||
}
|
||||
|
||||
public UserDetails getUserDetails() {
|
||||
return userDetails;
|
||||
}
|
||||
|
||||
public void setUserDetails(UserDetails userDetails) {
|
||||
this.userDetails = userDetails;
|
||||
}
|
||||
|
||||
public void setGrantedAuthority(ArrayList<GrantedAuthority> grantedAuthority) {
|
||||
this.grantedAuthority = grantedAuthority;
|
||||
}
|
||||
|
||||
public OnlineTicket getOnlineTicket() {
|
||||
return onlineTicket;
|
||||
}
|
||||
|
||||
public void setOnlineTicket(OnlineTicket onlineTicket) {
|
||||
this.onlineTicket = onlineTicket;
|
||||
}
|
||||
|
||||
public boolean isRoleAdministrators() {
|
||||
return roleAdministrators;
|
||||
}
|
||||
|
||||
public void setRoleAdministrators(boolean roleAdministrators) {
|
||||
this.roleAdministrators = roleAdministrators;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return this.accountNonExpired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return this.accountNonLocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return this.credentialsNonExpired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public ArrayList<GrantedAuthority> getGrantedAuthorityApps() {
|
||||
return grantedAuthorityApps;
|
||||
}
|
||||
|
||||
public void setGrantedAuthorityApps(ArrayList<GrantedAuthority> grantedAuthorityApps) {
|
||||
this.grantedAuthorityApps = grantedAuthorityApps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
if(this.userInfo != null) {
|
||||
return this.userInfo.getUsername();
|
||||
}else {
|
||||
return this.userDetails.getUsername();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
if(this.userInfo != null) {
|
||||
return this.userInfo.getPassword();
|
||||
}else {
|
||||
return this.userDetails.getPassword();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("SigninPrincipal [userInfo=");
|
||||
builder.append(userInfo);
|
||||
builder.append(", onlineTicket=");
|
||||
builder.append(onlineTicket);
|
||||
builder.append(", grantedAuthority=");
|
||||
builder.append(grantedAuthority);
|
||||
builder.append(", authenticated=");
|
||||
builder.append(authenticated);
|
||||
builder.append(", roleAdministrators=");
|
||||
builder.append(roleAdministrators);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.online;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalTime;
|
||||
|
||||
import org.ehcache.UserManagedCache;
|
||||
import org.ehcache.config.builders.ExpiryPolicyBuilder;
|
||||
import org.ehcache.config.builders.UserManagedCacheBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class InMemoryOnlineTicketServices implements OnlineTicketServices{
|
||||
private static final Logger _logger = LoggerFactory.getLogger(InMemoryOnlineTicketServices.class);
|
||||
|
||||
protected static UserManagedCache<String, OnlineTicket> onlineTicketStore =
|
||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, OnlineTicket.class)
|
||||
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(30)))
|
||||
.build(true);
|
||||
|
||||
|
||||
public InMemoryOnlineTicketServices() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(String ticketId, OnlineTicket ticket) {
|
||||
onlineTicketStore.put(ticketId, ticket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OnlineTicket remove(String ticketId) {
|
||||
OnlineTicket ticket=onlineTicketStore.get(ticketId);
|
||||
onlineTicketStore.remove(ticketId);
|
||||
return ticket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OnlineTicket get(String ticketId) {
|
||||
OnlineTicket ticket=onlineTicketStore.get(ticketId);
|
||||
return ticket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValiditySeconds(int validitySeconds) {
|
||||
onlineTicketStore =
|
||||
UserManagedCacheBuilder.
|
||||
newUserManagedCacheBuilder(String.class, OnlineTicket.class)
|
||||
.withExpiry(
|
||||
ExpiryPolicyBuilder.timeToLiveExpiration(
|
||||
Duration.ofMinutes(validitySeconds/60))
|
||||
)
|
||||
.build(true);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(String ticketId,LocalTime refreshTime) {
|
||||
OnlineTicket onlineTicket = get(ticketId);
|
||||
onlineTicket.setTicketTime(refreshTime);
|
||||
store(ticketId , onlineTicket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(String ticketId) {
|
||||
OnlineTicket onlineTicket = get(ticketId);
|
||||
|
||||
LocalTime currentTime = LocalTime.now();
|
||||
Duration duration = Duration.between(currentTime, onlineTicket.getTicketTime());
|
||||
|
||||
_logger.trace("OnlineTicket duration " + duration.getSeconds());
|
||||
|
||||
if(duration.getSeconds() > OnlineTicket.MAX_EXPIRY_DURATION) {
|
||||
onlineTicket.setTicketTime(currentTime);
|
||||
refresh(ticketId,currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.online;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalTime;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.maxkey.domain.apps.Apps;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
public class OnlineTicket implements Serializable{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
public static final int MAX_EXPIRY_DURATION = 60 * 10; //default 10 minutes.
|
||||
|
||||
private static final long serialVersionUID = 9008067569150338296L;
|
||||
|
||||
public String ticketId;
|
||||
|
||||
public LocalTime ticketTime;
|
||||
|
||||
public Authentication authentication;
|
||||
|
||||
private HashMap<String , Apps> authorizedApps = new HashMap<String , Apps>();
|
||||
|
||||
|
||||
public OnlineTicket(String ticketId) {
|
||||
super();
|
||||
this.ticketId = ticketId;
|
||||
this.ticketTime = LocalTime.now();
|
||||
}
|
||||
|
||||
public OnlineTicket(String ticketId,Authentication authentication) {
|
||||
super();
|
||||
this.ticketId = ticketId;
|
||||
this.authentication = authentication;
|
||||
this.ticketTime = LocalTime.now();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getTicketId() {
|
||||
return ticketId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setTicketId(String ticketId) {
|
||||
this.ticketId = ticketId;
|
||||
}
|
||||
|
||||
|
||||
public LocalTime getTicketTime() {
|
||||
return ticketTime;
|
||||
}
|
||||
|
||||
public void setTicketTime(LocalTime ticketTime) {
|
||||
this.ticketTime = ticketTime;
|
||||
}
|
||||
|
||||
public Authentication getAuthentication() {
|
||||
return authentication;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setAuthentication(Authentication authentication) {
|
||||
this.authentication = authentication;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public HashMap<String, Apps> getAuthorizedApps() {
|
||||
return authorizedApps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setAuthorizedApps(HashMap<String, Apps> authorizedApps) {
|
||||
this.authorizedApps = authorizedApps;
|
||||
}
|
||||
|
||||
public void setAuthorizedApp(Apps authorizedApp) {
|
||||
this.authorizedApps.put(authorizedApp.getId(), authorizedApp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("OnlineTicket [ticketId=");
|
||||
builder.append(ticketId);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.online;
|
||||
|
||||
import java.time.LocalTime;
|
||||
|
||||
public interface OnlineTicketServices {
|
||||
|
||||
public void store(String ticketId, OnlineTicket ticket);
|
||||
|
||||
public OnlineTicket remove(String ticket);
|
||||
|
||||
public OnlineTicket get(String ticketId);
|
||||
|
||||
public void refresh(String ticketId ,LocalTime refreshTime);
|
||||
|
||||
public void refresh(String ticketId);
|
||||
|
||||
public void setValiditySeconds(int validitySeconds);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.online;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalTime;
|
||||
|
||||
import org.maxkey.persistence.redis.RedisConnection;
|
||||
import org.maxkey.persistence.redis.RedisConnectionFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class RedisOnlineTicketServices implements OnlineTicketServices {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(RedisOnlineTicketServices.class);
|
||||
|
||||
protected int serviceTicketValiditySeconds = 60 * 30; //default 30 minutes.
|
||||
|
||||
RedisConnectionFactory connectionFactory;
|
||||
|
||||
public static String PREFIX="REDIS_ONLINE_TICKET_";
|
||||
/**
|
||||
* @param connectionFactory
|
||||
*/
|
||||
public RedisOnlineTicketServices(RedisConnectionFactory connectionFactory) {
|
||||
super();
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public RedisOnlineTicketServices() {
|
||||
|
||||
}
|
||||
|
||||
public void setConnectionFactory(RedisConnectionFactory connectionFactory) {
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(String ticketId, OnlineTicket ticket) {
|
||||
RedisConnection conn=connectionFactory.getConnection();
|
||||
conn.setexObject(PREFIX+ticketId, serviceTicketValiditySeconds, ticket);
|
||||
conn.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OnlineTicket remove(String ticketId) {
|
||||
RedisConnection conn=connectionFactory.getConnection();
|
||||
OnlineTicket ticket = conn.getObject(PREFIX+ticketId);
|
||||
conn.delete(PREFIX+ticketId);
|
||||
conn.close();
|
||||
return ticket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OnlineTicket get(String ticketId) {
|
||||
RedisConnection conn=connectionFactory.getConnection();
|
||||
OnlineTicket ticket = conn.getObject(PREFIX+ticketId);
|
||||
conn.close();
|
||||
return ticket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValiditySeconds(int validitySeconds) {
|
||||
this.serviceTicketValiditySeconds = validitySeconds;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(String ticketId,LocalTime refreshTime) {
|
||||
OnlineTicket onlineTicket = get(ticketId);
|
||||
onlineTicket.setTicketTime(refreshTime);
|
||||
store(ticketId , onlineTicket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(String ticketId) {
|
||||
OnlineTicket onlineTicket = get(ticketId);
|
||||
|
||||
LocalTime currentTime = LocalTime.now();
|
||||
Duration duration = Duration.between(currentTime, onlineTicket.getTicketTime());
|
||||
|
||||
_logger.trace("OnlineTicket duration " + duration.getSeconds());
|
||||
|
||||
if(duration.getSeconds() > OnlineTicket.MAX_EXPIRY_DURATION) {
|
||||
onlineTicket.setTicketTime(currentTime);
|
||||
refresh(ticketId,currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.realm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.maxkey.authn.support.rememberme.AbstractRemeberMeService;
|
||||
import org.maxkey.domain.Groups;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.persistence.db.LoginHistoryService;
|
||||
import org.maxkey.persistence.db.PasswordPolicyValidator;
|
||||
import org.maxkey.persistence.db.LoginService;
|
||||
import org.maxkey.util.DateUtils;
|
||||
import org.maxkey.web.WebConstants;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
/**
|
||||
* AbstractAuthenticationRealm.
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractAuthenticationRealm {
|
||||
private static Logger _logger = LoggerFactory.getLogger(AbstractAuthenticationRealm.class);
|
||||
|
||||
protected JdbcTemplate jdbcTemplate;
|
||||
|
||||
protected boolean provisioning;
|
||||
|
||||
@Autowired
|
||||
protected PasswordPolicyValidator passwordPolicyValidator;
|
||||
|
||||
@Autowired
|
||||
protected LoginService loginService;
|
||||
|
||||
@Autowired
|
||||
protected LoginHistoryService loginHistoryService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("remeberMeService")
|
||||
protected AbstractRemeberMeService remeberMeService;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public AbstractAuthenticationRealm() {
|
||||
|
||||
}
|
||||
|
||||
public AbstractAuthenticationRealm(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
public PasswordPolicyValidator getPasswordPolicyValidator() {
|
||||
return passwordPolicyValidator;
|
||||
}
|
||||
|
||||
public LoginService getUserInfoLoginService() {
|
||||
return loginService;
|
||||
}
|
||||
|
||||
public UserInfo loadUserInfo(String username, String password) {
|
||||
return loginService.loadUserInfo(username, password);
|
||||
}
|
||||
|
||||
public abstract boolean passwordMatches(UserInfo userInfo, String password);
|
||||
|
||||
|
||||
public static boolean isAuthenticated() {
|
||||
if (WebContext.getUserInfo() != null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<Groups> queryGroups(UserInfo userInfo) {
|
||||
return loginService.queryGroups(userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* grant Authority by userinfo
|
||||
*
|
||||
* @param userInfo
|
||||
* @return ArrayList<GrantedAuthority>
|
||||
*/
|
||||
public ArrayList<GrantedAuthority> grantAuthority(UserInfo userInfo) {
|
||||
return loginService.grantAuthority(userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* grant Authority by grantedAuthoritys
|
||||
*
|
||||
* @param grantedAuthoritys
|
||||
* @return ArrayList<GrantedAuthority Apps>
|
||||
*/
|
||||
public ArrayList<GrantedAuthority> queryAuthorizedApps(ArrayList<GrantedAuthority> grantedAuthoritys) {
|
||||
return loginService.queryAuthorizedApps(grantedAuthoritys);
|
||||
}
|
||||
|
||||
/**
|
||||
* login log write to log db
|
||||
*
|
||||
* @param uid
|
||||
* @param j_username
|
||||
* @param type
|
||||
* @param code
|
||||
* @param message
|
||||
*/
|
||||
public boolean insertLoginHistory(UserInfo userInfo, String type, String provider, String code, String message) {
|
||||
String sessionId = WebContext.genId();
|
||||
WebContext.setAttribute(WebConstants.CURRENT_USER_SESSION_ID, sessionId);
|
||||
userInfo.setLastLoginTime(DateUtils.formatDateTime(new Date()));
|
||||
userInfo.setLastLoginIp(WebContext.getRequestIpAddress());
|
||||
String platform = "";
|
||||
String browser = "";
|
||||
String userAgent = WebContext.getRequest().getHeader("User-Agent");
|
||||
String[] arrayUserAgent = null;
|
||||
if (userAgent.indexOf("MSIE") > 0) {
|
||||
arrayUserAgent = userAgent.split(";");
|
||||
browser = arrayUserAgent[1].trim();
|
||||
platform = arrayUserAgent[2].trim();
|
||||
} else if (userAgent.indexOf("Trident") > 0) {
|
||||
arrayUserAgent = userAgent.split(";");
|
||||
browser = "MSIE/" + arrayUserAgent[3].split("\\)")[0];
|
||||
;
|
||||
platform = arrayUserAgent[0].split("\\(")[1];
|
||||
} else if (userAgent.indexOf("Chrome") > 0) {
|
||||
arrayUserAgent = userAgent.split(" ");
|
||||
// browser=arrayUserAgent[8].trim();
|
||||
for (int i = 0; i < arrayUserAgent.length; i++) {
|
||||
if (arrayUserAgent[i].contains("Chrome")) {
|
||||
browser = arrayUserAgent[i].trim();
|
||||
browser = browser.substring(0, browser.indexOf('.'));
|
||||
}
|
||||
}
|
||||
platform = (arrayUserAgent[1].substring(1) + " " + arrayUserAgent[2] + " "
|
||||
+ arrayUserAgent[3].substring(0, arrayUserAgent[3].length() - 1)).trim();
|
||||
} else if (userAgent.indexOf("Firefox") > 0) {
|
||||
arrayUserAgent = userAgent.split(" ");
|
||||
for (int i = 0; i < arrayUserAgent.length; i++) {
|
||||
if (arrayUserAgent[i].contains("Firefox")) {
|
||||
browser = arrayUserAgent[i].trim();
|
||||
browser = browser.substring(0, browser.indexOf('.'));
|
||||
}
|
||||
}
|
||||
platform = (arrayUserAgent[1].substring(1) + " " + arrayUserAgent[2] + " "
|
||||
+ arrayUserAgent[3].substring(0, arrayUserAgent[3].length() - 1)).trim();
|
||||
|
||||
}
|
||||
|
||||
loginHistoryService.login(userInfo,sessionId, type, message, code, provider, browser, platform);
|
||||
|
||||
loginService.setLastLoginInfo(userInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* logout user and remove RemeberMe token
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
public boolean logout(HttpServletResponse response) {
|
||||
if (isAuthenticated()) {
|
||||
Object sessionIdAttribute = WebContext.getAttribute(WebConstants.CURRENT_USER_SESSION_ID);
|
||||
UserInfo userInfo = WebContext.getUserInfo();
|
||||
userInfo.setLastLogoffTime(DateUtils.formatDateTime(new Date()));
|
||||
|
||||
if (sessionIdAttribute != null) {
|
||||
remeberMeService.removeRemeberMe(response);
|
||||
|
||||
loginHistoryService.logoff(userInfo.getLastLogoffTime(), sessionIdAttribute.toString());
|
||||
}
|
||||
|
||||
loginService.setLastLogoffInfo(userInfo);
|
||||
|
||||
_logger.debug("Session " + WebContext.getAttribute(WebConstants.CURRENT_USER_SESSION_ID) + ", user "
|
||||
+ userInfo.getUsername() + " Logout, datetime " + userInfo.getLastLogoffTime() + " .");
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.realm;
|
||||
|
||||
/**
|
||||
* IAuthenticationServer .
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public interface IAuthenticationServer {
|
||||
|
||||
public boolean authenticate(String username, String password);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.realm.jdbc;
|
||||
|
||||
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
|
||||
import org.maxkey.constants.ConstantsLoginType;
|
||||
import org.maxkey.crypto.password.PasswordReciprocal;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
/**
|
||||
* same as JdbcAuthenticationRealm.
|
||||
*
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class DefaultJdbcAuthenticationRealm extends AbstractAuthenticationRealm {
|
||||
private static Logger _logger = LoggerFactory.getLogger(DefaultJdbcAuthenticationRealm.class);
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
public DefaultJdbcAuthenticationRealm() {
|
||||
|
||||
}
|
||||
|
||||
public DefaultJdbcAuthenticationRealm(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* passwordMatches.
|
||||
*/
|
||||
public boolean passwordMatches(UserInfo userInfo, String password) {
|
||||
boolean passwordMatches = false;
|
||||
_logger.info("password : "
|
||||
+ PasswordReciprocal.getInstance().rawPassword(userInfo.getUsername(), password));
|
||||
passwordMatches = passwordEncoder.matches(password,userInfo.getPassword());
|
||||
_logger.debug("passwordvalid : " + passwordMatches);
|
||||
if (!passwordMatches) {
|
||||
passwordPolicyValidator.setBadPasswordCount(userInfo);
|
||||
insertLoginHistory(userInfo, ConstantsLoginType.LOCAL, "", "xe00000004", "password error");
|
||||
throw new BadCredentialsException(WebContext.getI18nValue("login.error.password"));
|
||||
}
|
||||
return passwordMatches;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.realm.jdbc;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* JdbcAuthenticationRealm.
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class JdbcAuthenticationRealm extends DefaultJdbcAuthenticationRealm {
|
||||
private static Logger _logger = LoggerFactory.getLogger(JdbcAuthenticationRealm.class);
|
||||
|
||||
public JdbcAuthenticationRealm() {
|
||||
_logger.debug("init . ");
|
||||
}
|
||||
|
||||
public JdbcAuthenticationRealm(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.support.jwt;
|
||||
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jose.crypto.RSASSAVerifier;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.PlainJWT;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.joda.time.DateTime;
|
||||
import org.maxkey.authn.AbstractAuthenticationProvider;
|
||||
import org.maxkey.configuration.oidc.OIDCProviderMetadataDetails;
|
||||
import org.maxkey.constants.ConstantsLoginType;
|
||||
import org.maxkey.crypto.jwt.signer.service.impl.DefaultJwtSigningAndValidationService;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class JwtLoginService {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(JwtLoginService.class);
|
||||
|
||||
|
||||
OIDCProviderMetadataDetails jwtProviderMetadata;
|
||||
|
||||
DefaultJwtSigningAndValidationService jwtSignerValidationService;
|
||||
|
||||
AbstractAuthenticationProvider authenticationProvider ;
|
||||
|
||||
|
||||
public JwtLoginService(AbstractAuthenticationProvider authenticationProvider,
|
||||
OIDCProviderMetadataDetails jwtProviderMetadata,
|
||||
DefaultJwtSigningAndValidationService jwtSignerValidationService
|
||||
) {
|
||||
this.authenticationProvider = authenticationProvider;
|
||||
this.jwtProviderMetadata = jwtProviderMetadata;
|
||||
this.jwtSignerValidationService = jwtSignerValidationService;
|
||||
|
||||
}
|
||||
public boolean login(String jwt, HttpServletResponse response) {
|
||||
_logger.debug("jwt : " + jwt);
|
||||
|
||||
String username = null;
|
||||
SignedJWT signedJWT = null;
|
||||
|
||||
boolean loginResult = false;
|
||||
JWTClaimsSet jwtClaimsSet = null;
|
||||
try {
|
||||
|
||||
RSASSAVerifier rsaSSAVerifier = new RSASSAVerifier(((RSAKey) jwtSignerValidationService.getAllPublicKeys()
|
||||
.get(jwtSignerValidationService.getDefaultSignerKeyId())).toRSAPublicKey());
|
||||
|
||||
signedJWT = SignedJWT.parse(jwt);
|
||||
if (signedJWT.verify(rsaSSAVerifier)) {
|
||||
loginResult = true;
|
||||
} else {
|
||||
_logger.debug("verify false ");
|
||||
return false;
|
||||
}
|
||||
jwtClaimsSet = signedJWT.getJWTClaimsSet();
|
||||
|
||||
_logger.debug("" + signedJWT.getPayload());
|
||||
_logger.debug("jwtClaimsSet Issuer " + jwtClaimsSet.getIssuer());
|
||||
_logger.debug("Metadata Issuer " + jwtProviderMetadata.getIssuer());
|
||||
|
||||
if (loginResult && jwtClaimsSet.getIssuer().equals(jwtProviderMetadata.getIssuer())) {
|
||||
loginResult = true;
|
||||
_logger.debug("Issuer equals ");
|
||||
} else {
|
||||
_logger.debug("Issuer not equals ");
|
||||
return false;
|
||||
}
|
||||
|
||||
_logger.debug("username " + jwtClaimsSet.getSubject());
|
||||
|
||||
if (loginResult && jwtClaimsSet.getSubject() != null) {
|
||||
username = jwtClaimsSet.getSubject();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
DateTime now = new DateTime();
|
||||
|
||||
if (loginResult && now.isBefore(jwtClaimsSet.getExpirationTime().getTime())) {
|
||||
authenticationProvider.trustAuthentication(username, ConstantsLoginType.JWT, "", "", "success");
|
||||
return true;
|
||||
}
|
||||
} catch (java.text.ParseException e) {
|
||||
// Invalid signed JWT encoding
|
||||
_logger.error("Invalid signed JWT encoding ");
|
||||
} catch (JOSEException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
_logger.error("JOSEException ");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String buildLoginJwt() {
|
||||
_logger.debug("buildLoginJwt .");
|
||||
|
||||
DateTime currentDateTime = DateTime.now();
|
||||
Date expirationTime = currentDateTime.plusMinutes(5).toDate();
|
||||
_logger.debug("expiration Time : " + expirationTime);
|
||||
JWTClaimsSet jwtClaims = new JWTClaimsSet.Builder().subject(WebContext.getSession().getId())
|
||||
.expirationTime(expirationTime).issuer(jwtProviderMetadata.getIssuer())
|
||||
.issueTime(currentDateTime.toDate()).jwtID(UUID.randomUUID().toString()).build();
|
||||
|
||||
JWT jwtToken = new PlainJWT(jwtClaims);
|
||||
|
||||
_logger.info("jwt Claims : " + jwtClaims.toString());
|
||||
|
||||
JWSAlgorithm signingAlg = jwtSignerValidationService.getDefaultSigningAlgorithm();
|
||||
|
||||
jwtToken = new SignedJWT(new JWSHeader(signingAlg), jwtClaims);
|
||||
// sign it with the server's key
|
||||
jwtSignerValidationService.signJwt((SignedJWT) jwtToken);
|
||||
|
||||
String tokenString = jwtToken.serialize();
|
||||
_logger.debug("jwt Token : " + tokenString);
|
||||
return tokenString;
|
||||
}
|
||||
|
||||
public boolean jwtTokenValidation(String jwt) {
|
||||
SignedJWT signedJWT = null;
|
||||
|
||||
boolean loginResult = false;
|
||||
JWTClaimsSet jwtClaimsSet = null;
|
||||
try {
|
||||
|
||||
RSASSAVerifier rsaSSAVerifier = new RSASSAVerifier(((RSAKey) jwtSignerValidationService.getAllPublicKeys()
|
||||
.get(jwtSignerValidationService.getDefaultSignerKeyId())).toRSAPublicKey());
|
||||
|
||||
signedJWT = SignedJWT.parse(jwt);
|
||||
if (signedJWT.verify(rsaSSAVerifier)) {
|
||||
loginResult = true;
|
||||
} else {
|
||||
_logger.debug("verify false ");
|
||||
}
|
||||
jwtClaimsSet = signedJWT.getJWTClaimsSet();
|
||||
|
||||
_logger.debug("" + signedJWT.getPayload());
|
||||
|
||||
_logger.debug("username " + jwtClaimsSet.getSubject());
|
||||
|
||||
_logger.debug("jwtClaimsSet Issuer " + jwtClaimsSet.getIssuer());
|
||||
_logger.debug("Metadata Issuer " + jwtProviderMetadata.getIssuer());
|
||||
|
||||
if (loginResult && jwtClaimsSet.getIssuer().equals(jwtProviderMetadata.getIssuer())) {
|
||||
loginResult = true;
|
||||
_logger.debug("Issuer equals ");
|
||||
} else {
|
||||
_logger.debug("Issuer not equals ");
|
||||
return false;
|
||||
}
|
||||
|
||||
DateTime now = new DateTime();
|
||||
|
||||
if (loginResult && now.isBefore(jwtClaimsSet.getExpirationTime().getTime())) {
|
||||
_logger.debug("ExpirationTime Validation " + now.isBefore(jwtClaimsSet.getExpirationTime().getTime()));
|
||||
loginResult = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (java.text.ParseException e) {
|
||||
// Invalid signed JWT encoding
|
||||
_logger.debug("Invalid signed JWT encoding ");
|
||||
} catch (JOSEException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
_logger.debug("JOSEException ");
|
||||
}
|
||||
return loginResult;
|
||||
}
|
||||
|
||||
|
||||
public void setJwtProviderMetadata(OIDCProviderMetadataDetails jwtProviderMetadata) {
|
||||
this.jwtProviderMetadata = jwtProviderMetadata;
|
||||
}
|
||||
|
||||
public void setJwtSignerValidationService(DefaultJwtSigningAndValidationService jwtSignerValidationService) {
|
||||
this.jwtSignerValidationService = jwtSignerValidationService;
|
||||
}
|
||||
|
||||
public void setAuthenticationProvider(AbstractAuthenticationProvider authenticationProvider) {
|
||||
this.authenticationProvider = authenticationProvider;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.support.rememberme;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.joda.time.DateTime;
|
||||
import org.maxkey.authn.AbstractAuthenticationProvider;
|
||||
import org.maxkey.configuration.ApplicationConfig;
|
||||
import org.maxkey.constants.ConstantsLoginType;
|
||||
import org.maxkey.constants.ConstantsTimeInterval;
|
||||
import org.maxkey.crypto.Base64Utils;
|
||||
import org.maxkey.crypto.ReciprocalUtils;
|
||||
import org.maxkey.util.JsonUtils;
|
||||
import org.maxkey.web.WebConstants;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
public abstract class AbstractRemeberMeService {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(AbstractRemeberMeService.class);
|
||||
|
||||
protected Integer remeberMeValidity = ConstantsTimeInterval.TWO_WEEK;
|
||||
|
||||
protected String validity;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("applicationConfig")
|
||||
protected ApplicationConfig applicationConfig;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("authenticationProvider")
|
||||
AbstractAuthenticationProvider authenticationProvider ;
|
||||
|
||||
// follow function is for persist
|
||||
public abstract void save(RemeberMe remeberMe);
|
||||
|
||||
public abstract void update(RemeberMe remeberMe);
|
||||
|
||||
public abstract RemeberMe read(RemeberMe remeberMe);
|
||||
|
||||
public abstract void remove(String username);
|
||||
// end persist
|
||||
|
||||
public boolean createRemeberMe(String username, HttpServletRequest request, HttpServletResponse response) {
|
||||
if (request.getSession().getAttribute(WebConstants.REMEBER_ME_SESSION) != null
|
||||
&& applicationConfig.getLoginConfig().isRemeberMe()) {
|
||||
_logger.debug("Remeber Me ...");
|
||||
RemeberMe remeberMe = new RemeberMe();
|
||||
remeberMe.setAuthKey(WebContext.genId());
|
||||
remeberMe.setId(WebContext.genId());
|
||||
remeberMe.setUsername(WebContext.getUserInfo().getUsername());
|
||||
remeberMe.setLastLogin(new Date());
|
||||
save(remeberMe);
|
||||
_logger.debug("Remeber Me " + remeberMe);
|
||||
_logger.debug("Cookie Name : " + WebConstants.REMEBER_ME_COOKIE);
|
||||
|
||||
String jsonRemeberMe = JsonUtils.object2Json(remeberMe);
|
||||
_logger.debug("Remeber Me JSON " + jsonRemeberMe);
|
||||
|
||||
jsonRemeberMe = ReciprocalUtils.encode(jsonRemeberMe);
|
||||
|
||||
String cookieValue = Base64Utils.base64UrlEncode(jsonRemeberMe.getBytes());
|
||||
|
||||
_logger.debug("Remeber Me JSON " + cookieValue);
|
||||
Cookie cookie = new Cookie(WebConstants.REMEBER_ME_COOKIE, cookieValue);
|
||||
|
||||
Integer maxAge = getRemeberMeValidity();
|
||||
_logger.debug("Cookie Max Age :" + maxAge + " seconds.");
|
||||
cookie.setMaxAge(maxAge);
|
||||
|
||||
// cookie.setPath("/");
|
||||
cookie.setDomain(applicationConfig.getDomainName());
|
||||
response.addCookie(cookie);
|
||||
request.getSession().removeAttribute(WebConstants.REMEBER_ME_SESSION);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean login(String remeberMe, HttpServletResponse response) {
|
||||
_logger.debug("RemeberMe : " + remeberMe);
|
||||
|
||||
remeberMe = new String(Base64Utils.base64UrlDecode(remeberMe));
|
||||
|
||||
remeberMe = ReciprocalUtils.decoder(remeberMe);
|
||||
|
||||
_logger.debug("decoder RemeberMe : " + remeberMe);
|
||||
RemeberMe remeberMeCookie = new RemeberMe();
|
||||
remeberMeCookie = (RemeberMe) JsonUtils.json2Object(remeberMe, remeberMeCookie);
|
||||
_logger.debug("Remeber Me Cookie : " + remeberMeCookie);
|
||||
|
||||
RemeberMe storeRemeberMe = read(remeberMeCookie);
|
||||
if (storeRemeberMe == null) {
|
||||
return false;
|
||||
}
|
||||
DateTime loginDate = new DateTime(storeRemeberMe.getLastLogin());
|
||||
DateTime expiryDate = loginDate.plusSeconds(getRemeberMeValidity());
|
||||
DateTime now = new DateTime();
|
||||
if (now.isBefore(expiryDate)) {
|
||||
authenticationProvider.trustAuthentication(
|
||||
storeRemeberMe.getUsername(),
|
||||
ConstantsLoginType.REMEBER_ME,
|
||||
"",
|
||||
"",
|
||||
"success");
|
||||
return updateRemeberMe(remeberMeCookie, response);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean updateRemeberMe(RemeberMe remeberMe, HttpServletResponse response) {
|
||||
remeberMe.setAuthKey(WebContext.genId());
|
||||
remeberMe.setLastLogin(new Date());
|
||||
update(remeberMe);
|
||||
_logger.debug("update Remeber Me " + remeberMe);
|
||||
_logger.debug("Cookie Name : " + WebConstants.REMEBER_ME_COOKIE);
|
||||
|
||||
String jsonRemeberMe = JsonUtils.object2Json(remeberMe);
|
||||
_logger.debug("Remeber Me JSON " + jsonRemeberMe);
|
||||
|
||||
_logger.debug("Encode Remeber Me JSON ...");
|
||||
jsonRemeberMe = ReciprocalUtils.encode(jsonRemeberMe);
|
||||
_logger.debug("Encode Remeber Me JSON " + jsonRemeberMe);
|
||||
|
||||
String cookieValue = Base64Utils.base64UrlEncode(jsonRemeberMe.getBytes());
|
||||
|
||||
Cookie cookie = new Cookie(WebConstants.REMEBER_ME_COOKIE, cookieValue);
|
||||
|
||||
Integer maxAge = getRemeberMeValidity();
|
||||
_logger.debug("Cookie Max Age :" + maxAge + " seconds.");
|
||||
cookie.setMaxAge(maxAge);
|
||||
|
||||
// cookie.setPath("/");
|
||||
cookie.setDomain(applicationConfig.getDomainName());
|
||||
response.addCookie(cookie);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean removeRemeberMe(HttpServletResponse response) {
|
||||
Cookie cookie = new Cookie(WebConstants.REMEBER_ME_COOKIE, null);
|
||||
cookie.setMaxAge(0);
|
||||
|
||||
cookie.setDomain(applicationConfig.getDomainName());
|
||||
response.addCookie(cookie);
|
||||
|
||||
remove(WebContext.getUserInfo().getUsername());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Integer getRemeberMeValidity() {
|
||||
return remeberMeValidity;
|
||||
}
|
||||
|
||||
public void setRemeberMeValidity(Integer remeberMeValidity) {
|
||||
this.remeberMeValidity = remeberMeValidity;
|
||||
}
|
||||
|
||||
public String getValidity() {
|
||||
return validity;
|
||||
}
|
||||
|
||||
public void setApplicationConfig(ApplicationConfig applicationConfig) {
|
||||
this.applicationConfig = applicationConfig;
|
||||
}
|
||||
|
||||
public void setValidity(String validity) {
|
||||
_logger.debug("validity : " + validity);
|
||||
this.validity = validity;
|
||||
if (Pattern.matches("[0-9]+", validity)) {
|
||||
remeberMeValidity = Integer.parseInt(validity);
|
||||
} else if (validity.equalsIgnoreCase("ONE_DAY")) {
|
||||
remeberMeValidity = ConstantsTimeInterval.ONE_DAY;
|
||||
} else if (validity.equalsIgnoreCase("ONE_WEEK")) {
|
||||
remeberMeValidity = ConstantsTimeInterval.ONE_WEEK;
|
||||
} else if (validity.equalsIgnoreCase("TWO_WEEK")) {
|
||||
remeberMeValidity = ConstantsTimeInterval.TWO_WEEK;
|
||||
} else if (validity.equalsIgnoreCase("ONE_YEAR")) {
|
||||
remeberMeValidity = ConstantsTimeInterval.ONE_YEAR;
|
||||
}
|
||||
|
||||
_logger.debug("Remeber Me Validity : " + remeberMeValidity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.support.rememberme;
|
||||
|
||||
import java.time.Duration;
|
||||
import org.ehcache.UserManagedCache;
|
||||
import org.ehcache.config.builders.ExpiryPolicyBuilder;
|
||||
import org.ehcache.config.builders.UserManagedCacheBuilder;
|
||||
import org.maxkey.constants.ConstantsTimeInterval;
|
||||
|
||||
public class InMemoryRemeberMeService extends AbstractRemeberMeService {
|
||||
|
||||
protected static final UserManagedCache<String, RemeberMe> remeberMeStore =
|
||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, RemeberMe.class)
|
||||
.withExpiry(
|
||||
ExpiryPolicyBuilder.timeToLiveExpiration(
|
||||
Duration.ofMinutes(ConstantsTimeInterval.TWO_WEEK)
|
||||
)
|
||||
)
|
||||
.build(true);
|
||||
|
||||
@Override
|
||||
public void save(RemeberMe remeberMe) {
|
||||
remeberMeStore.put(remeberMe.getUsername(), remeberMe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(RemeberMe remeberMe) {
|
||||
remeberMeStore.put(remeberMe.getUsername(), remeberMe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemeberMe read(RemeberMe remeberMe) {
|
||||
return remeberMeStore.get(remeberMe.getUsername());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String username) {
|
||||
remeberMeStore.remove(username);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.support.rememberme;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
public class JdbcRemeberMeService extends AbstractRemeberMeService {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(JdbcRemeberMeService.class);
|
||||
|
||||
private static final String DEFAULT_DEFAULT_INSERT_STATEMENT =
|
||||
"INSERT INTO REMEMBER_ME(ID, USERNAME,AUTHKEY,LASTLOGIN)VALUES( ? , ? , ? , ?)";
|
||||
|
||||
private static final String DEFAULT_DEFAULT_SELECT_STATEMENT =
|
||||
"SELECT ID, USERNAME,AUTHKEY,LASTLOGIN FROM REMEMBER_ME "
|
||||
+ " WHERE ID = ? AND USERNAME = ? AND AUTHKEY = ?";
|
||||
|
||||
private static final String DEFAULT_DEFAULT_DELETE_STATEMENT =
|
||||
"DELETE FROM REMEMBER_ME WHERE USERNAME = ?";
|
||||
|
||||
private static final String DEFAULT_DEFAULT_UPDATE_STATEMENT =
|
||||
"UPDATE REMEMBER_ME SET AUTHKEY = ? , LASTLOGIN = ? WHERE ID = ?";
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public JdbcRemeberMeService(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(RemeberMe remeberMe) {
|
||||
jdbcTemplate.update(DEFAULT_DEFAULT_INSERT_STATEMENT,
|
||||
new Object[] { remeberMe.getId(), remeberMe.getUsername(), remeberMe.getAuthKey(),
|
||||
remeberMe.getLastLogin() },
|
||||
new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(RemeberMe remeberMe) {
|
||||
jdbcTemplate.update(DEFAULT_DEFAULT_UPDATE_STATEMENT,
|
||||
new Object[] {
|
||||
remeberMe.getAuthKey(),
|
||||
remeberMe.getLastLogin(),
|
||||
remeberMe.getId()
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemeberMe read(RemeberMe remeberMe) {
|
||||
List<RemeberMe> listRemeberMe = jdbcTemplate.query(DEFAULT_DEFAULT_SELECT_STATEMENT,
|
||||
new RowMapper<RemeberMe>() {
|
||||
public RemeberMe mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
RemeberMe remeberMe = new RemeberMe();
|
||||
remeberMe.setId(rs.getString(1));
|
||||
remeberMe.setUsername(rs.getString(2));
|
||||
remeberMe.setAuthKey(rs.getString(3));
|
||||
remeberMe.setLastLogin(rs.getDate(4));
|
||||
return remeberMe;
|
||||
}
|
||||
}, remeberMe.getId(), remeberMe.getUsername(), remeberMe.getAuthKey());
|
||||
_logger.debug("listRemeberMe " + listRemeberMe);
|
||||
return (listRemeberMe.size() > 0) ? listRemeberMe.get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String username) {
|
||||
jdbcTemplate.update(DEFAULT_DEFAULT_DELETE_STATEMENT, username);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.support.rememberme;
|
||||
|
||||
import org.maxkey.constants.ConstantsTimeInterval;
|
||||
import org.maxkey.persistence.redis.RedisConnection;
|
||||
import org.maxkey.persistence.redis.RedisConnectionFactory;
|
||||
|
||||
public class RedisRemeberMeService extends AbstractRemeberMeService {
|
||||
|
||||
protected int serviceTicketValiditySeconds = ConstantsTimeInterval.TWO_WEEK;
|
||||
|
||||
RedisConnectionFactory connectionFactory;
|
||||
|
||||
public static String PREFIX = "REDIS_REMEBER_ME_SERVICE_";
|
||||
|
||||
@Override
|
||||
public void save(RemeberMe remeberMe) {
|
||||
RedisConnection conn = connectionFactory.getConnection();
|
||||
conn.setexObject(PREFIX + remeberMe.getUsername(), serviceTicketValiditySeconds, remeberMe);
|
||||
conn.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(RemeberMe remeberMe) {
|
||||
RedisConnection conn = connectionFactory.getConnection();
|
||||
conn.setexObject(PREFIX + remeberMe.getUsername(), serviceTicketValiditySeconds, remeberMe);
|
||||
conn.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemeberMe read(RemeberMe remeberMe) {
|
||||
RedisConnection conn = connectionFactory.getConnection();
|
||||
RemeberMe readRemeberMe = (RemeberMe)conn.getObject(PREFIX + remeberMe.getUsername());
|
||||
conn.close();
|
||||
return readRemeberMe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String username) {
|
||||
RedisConnection conn = connectionFactory.getConnection();
|
||||
conn.delete(PREFIX + username);
|
||||
conn.close();
|
||||
}
|
||||
|
||||
public RedisRemeberMeService(RedisConnectionFactory connectionFactory) {
|
||||
super();
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
public void setConnectionFactory(RedisConnectionFactory connectionFactory) {
|
||||
this.connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.authn.support.rememberme;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
public class RemeberMe implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8010496585233991785L;
|
||||
|
||||
String id;
|
||||
|
||||
String username;
|
||||
|
||||
String authKey;
|
||||
|
||||
Date lastLogin;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getAuthKey() {
|
||||
return authKey;
|
||||
}
|
||||
|
||||
public void setAuthKey(String authKey) {
|
||||
this.authKey = authKey;
|
||||
}
|
||||
|
||||
public Date getLastLogin() {
|
||||
return lastLogin;
|
||||
}
|
||||
|
||||
public void setLastLogin(Date lastLogin) {
|
||||
this.lastLogin = lastLogin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RemeberMe [id=" + id
|
||||
+ ", username=" + username
|
||||
+ ", authKey=" + authKey + ", lastLogin=" + lastLogin
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.autoconfigure;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.sql.DataSource;
|
||||
import org.maxkey.authn.AbstractAuthenticationProvider;
|
||||
import org.maxkey.authn.RealmAuthenticationProvider;
|
||||
import org.maxkey.authn.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.maxkey.authn.online.InMemoryOnlineTicketServices;
|
||||
import org.maxkey.authn.online.OnlineTicketServices;
|
||||
import org.maxkey.authn.online.RedisOnlineTicketServices;
|
||||
import org.maxkey.authn.support.rememberme.AbstractRemeberMeService;
|
||||
import org.maxkey.authn.support.rememberme.InMemoryRemeberMeService;
|
||||
import org.maxkey.authn.support.rememberme.RedisRemeberMeService;
|
||||
import org.maxkey.constants.ConstantsPersistence;
|
||||
import org.maxkey.constants.ConstantsProperties;
|
||||
import org.maxkey.crypto.password.LdapShaPasswordEncoder;
|
||||
import org.maxkey.crypto.password.Md4PasswordEncoder;
|
||||
import org.maxkey.crypto.password.NoOpPasswordEncoder;
|
||||
import org.maxkey.crypto.password.MessageDigestPasswordEncoder;
|
||||
import org.maxkey.crypto.password.SM3PasswordEncoder;
|
||||
import org.maxkey.crypto.password.StandardPasswordEncoder;
|
||||
import org.maxkey.persistence.db.PasswordPolicyValidator;
|
||||
import org.maxkey.persistence.redis.RedisConnectionFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
|
||||
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
|
||||
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
|
||||
import org.maxkey.persistence.db.LoginService;
|
||||
import org.maxkey.persistence.db.LoginHistoryService;
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(ConstantsProperties.applicationPropertySource)
|
||||
@PropertySource(ConstantsProperties.maxKeyPropertySource)
|
||||
public class AuthenticationAutoConfiguration implements InitializingBean {
|
||||
private static final Logger _logger =
|
||||
LoggerFactory.getLogger(AuthenticationAutoConfiguration.class);
|
||||
|
||||
|
||||
@Bean(name = "savedRequestSuccessHandler")
|
||||
public SavedRequestAwareAuthenticationSuccessHandler
|
||||
savedRequestAwareAuthenticationSuccessHandler() {
|
||||
return new SavedRequestAwareAuthenticationSuccessHandler();
|
||||
}
|
||||
|
||||
@Bean(name = "authenticationProvider")
|
||||
public AbstractAuthenticationProvider authenticationProvider() {
|
||||
return new RealmAuthenticationProvider();
|
||||
}
|
||||
|
||||
@Bean(name = "transactionManager")
|
||||
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
|
||||
return new DataSourceTransactionManager(dataSource);
|
||||
}
|
||||
|
||||
@Bean(name = "passwordPolicyValidator")
|
||||
public PasswordPolicyValidator passwordPolicyValidator(JdbcTemplate jdbcTemplate,MessageSource messageSource) {
|
||||
return new PasswordPolicyValidator(jdbcTemplate,messageSource);
|
||||
}
|
||||
|
||||
@Bean(name = "loginService")
|
||||
public LoginService LoginService(JdbcTemplate jdbcTemplate) {
|
||||
return new LoginService(jdbcTemplate);
|
||||
}
|
||||
@Bean(name = "loginHistoryService")
|
||||
public LoginHistoryService loginHistoryService(JdbcTemplate jdbcTemplate) {
|
||||
return new LoginHistoryService(jdbcTemplate);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Authentication Password Encoder .
|
||||
* @return
|
||||
*/
|
||||
@Bean(name = "passwordEncoder")
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
String idForEncode = "bcrypt";
|
||||
Map<String ,PasswordEncoder > encoders = new HashMap<String ,PasswordEncoder>();
|
||||
encoders.put(idForEncode, new BCryptPasswordEncoder());
|
||||
encoders.put("plain", NoOpPasswordEncoder.getInstance());
|
||||
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
|
||||
encoders.put("scrypt", new SCryptPasswordEncoder());
|
||||
//md
|
||||
encoders.put("md4", new Md4PasswordEncoder());
|
||||
encoders.put("md5", new MessageDigestPasswordEncoder("MD5"));
|
||||
//sha
|
||||
encoders.put("sha1", new StandardPasswordEncoder("SHA-1",""));
|
||||
encoders.put("sha256", new StandardPasswordEncoder());
|
||||
encoders.put("sha384", new StandardPasswordEncoder("SHA-384",""));
|
||||
encoders.put("sha512", new StandardPasswordEncoder("SHA-512",""));
|
||||
|
||||
encoders.put("sm3", new SM3PasswordEncoder());
|
||||
|
||||
encoders.put("ldap", new LdapShaPasswordEncoder());
|
||||
|
||||
//idForEncode is default for encoder
|
||||
PasswordEncoder passwordEncoder =
|
||||
new DelegatingPasswordEncoder(idForEncode, encoders);
|
||||
|
||||
return passwordEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* remeberMeService .
|
||||
* @return
|
||||
*/
|
||||
@Bean(name = "remeberMeService")
|
||||
public AbstractRemeberMeService remeberMeService(
|
||||
@Value("${config.server.persistence}") int persistence,
|
||||
@Value("${config.login.remeberme.validity}") int validity,
|
||||
JdbcTemplate jdbcTemplate,
|
||||
RedisConnectionFactory redisConnFactory) {
|
||||
AbstractRemeberMeService remeberMeService = null;
|
||||
if (persistence == ConstantsPersistence.INMEMORY) {
|
||||
remeberMeService = new InMemoryRemeberMeService();
|
||||
_logger.debug("InMemoryRemeberMeService");
|
||||
} else if (persistence == ConstantsPersistence.JDBC) {
|
||||
//remeberMeService = new JdbcRemeberMeService(jdbcTemplate);
|
||||
_logger.debug("JdbcRemeberMeService not support ");
|
||||
} else if (persistence == ConstantsPersistence.REDIS) {
|
||||
remeberMeService = new RedisRemeberMeService(redisConnFactory);
|
||||
_logger.debug("RedisRemeberMeService");
|
||||
}
|
||||
return remeberMeService;
|
||||
}
|
||||
|
||||
@Bean(name = "onlineTicketServices")
|
||||
public OnlineTicketServices onlineTicketServices(
|
||||
@Value("${config.server.persistence}") int persistence,
|
||||
JdbcTemplate jdbcTemplate,
|
||||
RedisConnectionFactory redisConnFactory) {
|
||||
OnlineTicketServices onlineTicketServices = null;
|
||||
if (persistence == ConstantsPersistence.INMEMORY) {
|
||||
onlineTicketServices = new InMemoryOnlineTicketServices();
|
||||
_logger.debug("InMemoryOnlineTicketServices");
|
||||
} else if (persistence == ConstantsPersistence.JDBC) {
|
||||
_logger.debug("OnlineTicketServices not support ");
|
||||
} else if (persistence == ConstantsPersistence.REDIS) {
|
||||
onlineTicketServices = new RedisOnlineTicketServices(redisConnFactory);
|
||||
_logger.debug("RedisOnlineTicketServices");
|
||||
}
|
||||
return onlineTicketServices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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 org.maxkey.autoconfigure;
|
||||
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
import java.net.URI;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
import org.maxkey.authn.AbstractAuthenticationProvider;
|
||||
import org.maxkey.authn.support.jwt.JwtLoginService;
|
||||
import org.maxkey.configuration.oidc.OIDCProviderMetadataDetails;
|
||||
import org.maxkey.constants.ConstantsProperties;
|
||||
import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
|
||||
import org.maxkey.crypto.jwt.encryption.service.impl.DefaultJwtEncryptionAndDecryptionService;
|
||||
import org.maxkey.crypto.jwt.signer.service.impl.DefaultJwtSigningAndValidationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
|
||||
@Configuration
|
||||
@PropertySource(ConstantsProperties.applicationPropertySource)
|
||||
@PropertySource(ConstantsProperties.maxKeyPropertySource)
|
||||
public class JwtAuthnAutoConfiguration implements InitializingBean {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(JwtAuthnAutoConfiguration.class);
|
||||
|
||||
/**
|
||||
* OIDCProviderMetadataDetails.
|
||||
* Self-issued Provider Metadata
|
||||
* http://openid.net/specs/openid-connect-core-1_0.html#SelfIssued
|
||||
*/
|
||||
@Bean(name = "oidcProviderMetadata")
|
||||
public OIDCProviderMetadataDetails OIDCProviderMetadataDetails(
|
||||
@Value("${config.oidc.metadata.issuer}")
|
||||
String issuer,
|
||||
@Value("${config.oidc.metadata.authorizationEndpoint}")
|
||||
URI authorizationEndpoint,
|
||||
@Value("${config.oidc.metadata.tokenEndpoint}")
|
||||
URI tokenEndpoint,
|
||||
@Value("${config.oidc.metadata.userinfoEndpoint}")
|
||||
URI userinfoEndpoint) {
|
||||
_logger.debug("RedisConnectionFactory init .");
|
||||
OIDCProviderMetadataDetails oidcProviderMetadata = new OIDCProviderMetadataDetails();
|
||||
oidcProviderMetadata.setIssuer(issuer);
|
||||
oidcProviderMetadata.setAuthorizationEndpoint(authorizationEndpoint);
|
||||
oidcProviderMetadata.setTokenEndpoint(tokenEndpoint);
|
||||
oidcProviderMetadata.setUserinfoEndpoint(userinfoEndpoint);
|
||||
return oidcProviderMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* jwtSetKeyStore.
|
||||
* @return
|
||||
*/
|
||||
@Bean(name = "jwkSetKeyStore")
|
||||
public JWKSetKeyStore jwtSetKeyStore() {
|
||||
JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore();
|
||||
ClassPathResource classPathResource = new ClassPathResource("/config/keystore.jwks");
|
||||
jwkSetKeyStore.setLocation(classPathResource);
|
||||
return jwkSetKeyStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* jwtSetKeyStore.
|
||||
* @return
|
||||
* @throws JOSEException
|
||||
* @throws InvalidKeySpecException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
@Bean(name = "jwtSignerValidationService")
|
||||
public DefaultJwtSigningAndValidationService jwtSignerValidationService(
|
||||
JWKSetKeyStore jwtSetKeyStore)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException {
|
||||
DefaultJwtSigningAndValidationService jwtSignerValidationService =
|
||||
new DefaultJwtSigningAndValidationService(jwtSetKeyStore);
|
||||
jwtSignerValidationService.setDefaultSignerKeyId("maxkey_rsa");
|
||||
jwtSignerValidationService.setDefaultSigningAlgorithmName("RS256");
|
||||
return jwtSignerValidationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* jwtSetKeyStore.
|
||||
* @return
|
||||
* @throws JOSEException
|
||||
* @throws InvalidKeySpecException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
@Bean(name = "jwtEncryptionService")
|
||||
public DefaultJwtEncryptionAndDecryptionService jwtEncryptionService(
|
||||
JWKSetKeyStore jwtSetKeyStore)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException {
|
||||
DefaultJwtEncryptionAndDecryptionService jwtEncryptionService =
|
||||
new DefaultJwtEncryptionAndDecryptionService(jwtSetKeyStore);
|
||||
jwtEncryptionService.setDefaultAlgorithm(JWEAlgorithm.RSA1_5);//RSA1_5
|
||||
jwtEncryptionService.setDefaultDecryptionKeyId("maxkey_rsa");
|
||||
jwtEncryptionService.setDefaultEncryptionKeyId("maxkey_rsa");
|
||||
return jwtEncryptionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* JwtLoginService.
|
||||
* @return
|
||||
*/
|
||||
@Bean(name = "jwtLoginService")
|
||||
public JwtLoginService jwtLoginService(
|
||||
DefaultJwtSigningAndValidationService jwtSignerValidationService,
|
||||
OIDCProviderMetadataDetails oidcProviderMetadata,
|
||||
AbstractAuthenticationProvider authenticationProvider) {
|
||||
|
||||
JwtLoginService jwtLoginService = new JwtLoginService(
|
||||
authenticationProvider,
|
||||
oidcProviderMetadata,
|
||||
jwtSignerValidationService
|
||||
);
|
||||
|
||||
return jwtLoginService;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user