separate common

This commit is contained in:
MaxKey
2021-02-15 10:47:29 +08:00
parent 647d899771
commit 9770acf991
37 changed files with 195 additions and 86 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
+ "]";
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}