Authentication 优化

This commit is contained in:
Crystal.Sea
2020-11-08 13:05:30 +08:00
parent c1e4b36cbe
commit 06b27d3564
41 changed files with 425 additions and 163 deletions

View File

@@ -18,7 +18,6 @@
package org.maxkey.authn;
import java.util.ArrayList;
import org.maxkey.authn.online.OnlineTicketServices;
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
import org.maxkey.authn.support.rememberme.AbstractRemeberMeService;
@@ -39,7 +38,6 @@ 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.
*
@@ -78,9 +76,9 @@ public abstract class AbstractAuthenticationProvider {
protected abstract String getProviderName();
protected abstract Authentication doInternalAuthenticate(Authentication authentication);
protected abstract Authentication doInternalAuthenticate(LoginCredential authentication);
public abstract Authentication basicAuthenticate(Authentication authentication) ;
public abstract Authentication basicAuthenticate(LoginCredential authentication) ;
public abstract Authentication trustAuthentication(
String username,
@@ -98,17 +96,18 @@ public abstract class AbstractAuthenticationProvider {
* authenticate .
*
*/
public Authentication authenticate(Authentication authentication)
public Authentication authenticate(LoginCredential loginCredential)
throws AuthenticationException {
_logger.debug("Trying to authenticate user '{}' via {}",
authentication.getPrincipal(), getProviderName());
loginCredential.getPrincipal(), getProviderName());
Authentication authentication = null;
try {
authentication = doInternalAuthenticate(authentication);
authentication = doInternalAuthenticate(loginCredential);
} catch (AuthenticationException e) {
_logger.error("Failed to authenticate user {} via {}: {}",
new Object[] {
authentication.getPrincipal(), getProviderName(), e.getMessage() });
new Object[] { loginCredential.getPrincipal(),
getProviderName(),
e.getMessage() });
WebContext.setAttribute(
WebConstants.LOGIN_ERROR_SESSION_MESSAGE, e.getMessage());
} catch (Exception e) {
@@ -131,7 +130,7 @@ public abstract class AbstractAuthenticationProvider {
final Object firstSavedRequest =
WebContext.getAttribute(WebConstants.FIRST_SAVED_REQUEST_PARAMETER);
//change Session
WebContext.getSession().invalidate();
WebContext.setAttribute(
WebConstants.CURRENT_USER_SESSION_ID, WebContext.getSession().getId());
@@ -147,14 +146,7 @@ public abstract class AbstractAuthenticationProvider {
WebContext.getSession().setAttribute(
WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE, passwordSetType);
// create new authentication response containing the user and it's authorities
UsernamePasswordAuthenticationToken simpleUserAuthentication =
new UsernamePasswordAuthenticationToken(
userInfo.getUsername(),
authentication.getCredentials(),
authentication.getAuthorities()
);
return simpleUserAuthentication;
return authentication;
}
/**

View File

@@ -1,32 +1,17 @@
/*
* 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.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
public class BasicAuthentication implements Authentication {
private static final long serialVersionUID = -110742975439268030L;
public class LoginCredential implements Authentication {
/**
*
*/
private static final long serialVersionUID = 3125709257481600320L;
String username;
String password;
String sessionId;
@@ -35,7 +20,7 @@ public class BasicAuthentication implements Authentication {
String remeberMe;
String authType;
String jwtToken;
OnlineTicket onlineTicket;
String onlineTicket;
ArrayList<GrantedAuthority> grantedAuthority;
boolean authenticated;
boolean roleAdministrators;
@@ -43,20 +28,21 @@ public class BasicAuthentication implements Authentication {
/**
* BasicAuthentication.
*/
public BasicAuthentication() {
public LoginCredential() {
}
/**
* BasicAuthentication.
*/
public BasicAuthentication(String username,String password,String authType) {
public LoginCredential(String username,String password,String authType) {
this.username = username;
this.password = password;
this.authType = authType;
}
@Override
public String getName() {
return "Basic Authentication";
return "Login Credential";
}
@Override
@@ -163,11 +149,11 @@ public class BasicAuthentication implements Authentication {
this.grantedAuthority = grantedAuthority;
}
public OnlineTicket getOnlineTicket() {
public String getOnlineTicket() {
return onlineTicket;
}
public void setOnlineTicket(OnlineTicket onlineTicket) {
public void setOnlineTicket(String onlineTicket) {
this.onlineTicket = onlineTicket;
}

View File

@@ -49,41 +49,40 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
}
@Override
protected Authentication doInternalAuthenticate(Authentication authentication) {
BasicAuthentication auth = (BasicAuthentication)authentication;
protected Authentication doInternalAuthenticate(LoginCredential loginCredential) {
_logger.debug("authentication " + auth);
_logger.debug("authentication " + loginCredential);
sessionValid(auth.getSessionId());
sessionValid(loginCredential.getSessionId());
//jwtTokenValid(j_jwtToken);
authTypeValid(auth.getAuthType());
authTypeValid(loginCredential.getAuthType());
captchaValid(auth.getCaptcha(),auth.getAuthType());
captchaValid(loginCredential.getCaptcha(),loginCredential.getAuthType());
emptyPasswordValid(auth.getPassword());
emptyPasswordValid(loginCredential.getPassword());
UserInfo userInfo = null;
emptyUsernameValid(auth.getUsername());
emptyUsernameValid(loginCredential.getUsername());
userInfo = loadUserInfo(auth.getUsername(),auth.getPassword());
userInfo = loadUserInfo(loginCredential.getUsername(),loginCredential.getPassword());
userinfoValid(userInfo, auth.getPassword());
userinfoValid(userInfo, loginCredential.getPassword());
tftcaptchaValid(auth.getOtpCaptcha(),auth.getAuthType(),userInfo);
tftcaptchaValid(loginCredential.getOtpCaptcha(),loginCredential.getAuthType(),userInfo);
authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(userInfo);
authenticationRealm.passwordMatches(userInfo, auth.getPassword());
authenticationRealm.passwordMatches(userInfo, loginCredential.getPassword());
UsernamePasswordAuthenticationToken authenticationToken = setOnline(auth,userInfo);
UsernamePasswordAuthenticationToken authenticationToken = setOnline(loginCredential,userInfo);
//RemeberMe Config check then set RemeberMe cookies
if (applicationConfig.getLoginConfig().isRemeberMe()) {
if (auth.getRemeberMe() != null && auth.getRemeberMe().equals("remeberMe")) {
if (loginCredential.getRemeberMe() != null && loginCredential.getRemeberMe().equals("remeberMe")) {
WebContext.getSession().setAttribute(
WebConstants.REMEBER_ME_SESSION,auth.getUsername());
WebConstants.REMEBER_ME_SESSION,loginCredential.getUsername());
_logger.debug("do Remeber Me");
remeberMeService.createRemeberMe(
userInfo.getUsername(),
@@ -98,20 +97,19 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
}
@Override
public Authentication basicAuthenticate(Authentication authentication) {
BasicAuthentication auth = (BasicAuthentication) authentication;
UserInfo loadeduserInfo = loadUserInfo(auth.getUsername(), "");
public Authentication basicAuthenticate(LoginCredential loginCredential) {
UserInfo loadeduserInfo = loadUserInfo(loginCredential.getUsername(), "");
if (loadeduserInfo != null) {
authenticationRealm.passwordMatches(loadeduserInfo, auth.getPassword());
authenticationRealm.passwordMatches(loadeduserInfo, loginCredential.getPassword());
authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(loadeduserInfo);
authenticationRealm.insertLoginHistory(loadeduserInfo, auth.getAuthType(), "", "", "SUCCESS");
authenticationRealm.insertLoginHistory(loadeduserInfo, loginCredential.getAuthType(), "", "", "SUCCESS");
return setOnline(auth,loadeduserInfo);
return setOnline(loginCredential,loadeduserInfo);
}else {
String message = WebContext.getI18nValue("login.error.username");
_logger.debug("login user " + auth.getUsername() + " not in this System ." + message);
_logger.debug("login user " + loginCredential.getUsername() + " not in this System ." + message);
throw new BadCredentialsException(WebContext.getI18nValue("login.error.username"));
}
}
@@ -133,12 +131,12 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
String message) {
UserInfo loadeduserInfo = loadUserInfo(username, "");
if (loadeduserInfo != null) {
BasicAuthentication auth = new BasicAuthentication();
auth.setUsername(loadeduserInfo.getUsername());
LoginCredential loginCredential = new LoginCredential();
loginCredential.setUsername(loadeduserInfo.getUsername());
authenticationRealm.insertLoginHistory(loadeduserInfo, type, provider, code, message);
return setOnline(auth,loadeduserInfo);
return setOnline(loginCredential,loadeduserInfo);
}else {
String i18nMessage = WebContext.getI18nValue("login.error.username");
_logger.debug("login user " + username + " not in this System ." + i18nMessage);
@@ -146,7 +144,7 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
}
}
public UsernamePasswordAuthenticationToken setOnline(BasicAuthentication authentication,UserInfo userInfo) {
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());
@@ -157,27 +155,26 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
onlineTickitId,
0);
SigninPrincipal signinPrincipal = new SigninPrincipal(userInfo);
//set OnlineTicket
OnlineTicket onlineTicket = new OnlineTicket(onlineTickitId,authentication);
this.onlineTicketServices.store(onlineTickitId, onlineTicket);
authentication.setOnlineTicket(onlineTicket);
signinPrincipal.setOnlineTicket(onlineTickitId);
ArrayList<GrantedAuthority> grantedAuthoritys = authenticationRealm.grantAuthority(userInfo);
//set default roles
grantedAuthoritys.add(new SimpleGrantedAuthority("ROLE_USER"));
grantedAuthoritys.add(new SimpleGrantedAuthority("ROLE_ORDINARY_USER"));
authentication.setAuthenticated(true);
signinPrincipal.setAuthenticated(true);
for(GrantedAuthority administratorsAuthority : grantedAdministratorsAuthoritys) {
if(grantedAuthoritys.contains(administratorsAuthority)) {
authentication.setRoleAdministrators(true);
signinPrincipal.setRoleAdministrators(true);
_logger.trace("ROLE ADMINISTRATORS Authentication .");
}
}
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(
authentication,
signinPrincipal,
"PASSWORD",
grantedAuthoritys
);
@@ -185,12 +182,13 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
authenticationToken.setDetails(
new WebAuthenticationDetails(WebContext.getRequest()));
OnlineTicket onlineTicket = new OnlineTicket(onlineTickitId,authenticationToken);
this.onlineTicketServices.store(onlineTickitId, onlineTicket);
/*
* put userInfo to current session context
*/
WebContext.setAuthentication(authenticationToken);
userInfo.setOnlineTicket(onlineTicket);
WebContext.setUserInfo(userInfo);
return authenticationToken;

View File

@@ -0,0 +1,172 @@
/*
* 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.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;
String onlineTicket;
ArrayList<GrantedAuthority> grantedAuthority;
boolean authenticated;
boolean roleAdministrators;
/**
* SigninPrincipal.
*/
public SigninPrincipal() {
}
/**
* SigninPrincipal.
*/
public SigninPrincipal(UserInfo userInfo) {
this.userInfo = userInfo;
this.authenticated = 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 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 boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
@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

@@ -20,6 +20,9 @@ package org.maxkey.autoconfigure;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import org.maxkey.constants.ConstantsProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -28,6 +31,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@@ -39,7 +43,9 @@ import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
@@ -244,6 +250,25 @@ public class MvcAutoConfiguration implements InitializingBean {
};
}
@Bean
public SecurityContextHolderAwareRequestFilter securityContextHolderAwareRequestFilter() {
_logger.debug("securityContextHolderAwareRequestFilter init ");
return new SecurityContextHolderAwareRequestFilter();
}
@Bean
public FilterRegistrationBean<Filter> delegatingFilterProxy() {
_logger.debug("delegatingFilterProxy init for /* ");
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<Filter>();
registrationBean.setFilter(new DelegatingFilterProxy("securityContextHolderAwareRequestFilter"));
registrationBean.addUrlPatterns("/*");
//registrationBean.
registrationBean.setName("delegatingFilterProxy");
registrationBean.setOrder(1);
return registrationBean;
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub

View File

@@ -26,7 +26,6 @@ import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.mybatis.jpa.persistence.JpaBaseDomain;
import org.maxkey.authn.online.OnlineTicket;
import org.maxkey.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
@@ -230,8 +229,6 @@ public class UserInfo extends JpaBaseDomain {
protected HashMap<String, String> extraAttributeMap;
protected int online;
OnlineTicket onlineTicket;
protected String ldapDn;
@@ -1165,14 +1162,6 @@ public class UserInfo extends JpaBaseDomain {
this.createdBy = createdBy;
}
public OnlineTicket getOnlineTicket() {
return onlineTicket;
}
public void setOnlineTicket(OnlineTicket onlineTicket) {
this.onlineTicket = onlineTicket;
}
/**
* @return the createdDate
*/

View File

@@ -153,6 +153,8 @@ public class Apps extends JpaBaseDomain implements Serializable {
protected String loginDateTime;
protected String onlineTicket;
public Apps() {
super();
isSignature = Boolean.FALSE;
@@ -549,6 +551,14 @@ public class Apps extends JpaBaseDomain implements Serializable {
this.loginDateTime = loginDateTime;
}
public String getOnlineTicket() {
return onlineTicket;
}
public void setOnlineTicket(String onlineTicket) {
this.onlineTicket = onlineTicket;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();

View File

@@ -36,6 +36,7 @@ import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
@@ -57,7 +58,10 @@ public class InitializeContext extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
_logger.info("SecurityContextHolder StrategyName " + SessionSecurityContextHolderStrategy.class.getCanonicalName());
SecurityContextHolder.setStrategyName(SessionSecurityContextHolderStrategy.class.getCanonicalName());
// List Environment Variables
listEnvVars();

View File

@@ -0,0 +1,51 @@
package org.maxkey.web;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl;
/**
* SecurityContext Session for Request , use SecurityContextHolderAwareRequestFilter
* @author Crystal.Sea
*
*/
public class SessionSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
private static final Logger _logger =
LoggerFactory.getLogger(SessionSecurityContextHolderStrategy.class);
@Override
public void clearContext() {
WebContext.removeAttribute(WebConstants.AUTHENTICATION);
}
@Override
public SecurityContext getContext() {
SecurityContext ctx = createEmptyContext();
Authentication authentication = null;
try {
authentication = (Authentication)WebContext.getAuthentication();
if (authentication != null) {
ctx.setAuthentication(authentication);
}
}catch(Exception e) {
_logger.trace("a session ", e);
}
return ctx;
}
@Override
public void setContext(SecurityContext context) {
WebContext.setAuthentication(context.getAuthentication());
}
@Override
public SecurityContext createEmptyContext() {
return new SecurityContextImpl();
}
}