mirror of
https://gitee.com/dromara/MaxKey.git
synced 2025-12-08 01:48:33 +08:00
Provider
This commit is contained in:
parent
586e473e48
commit
7bba47a46c
@ -3,6 +3,9 @@ description = "maxkey-authentication-captcha"
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation project(":maxkey-common")
|
||||
implementation project(":maxkey-core")
|
||||
implementation project(":maxkey-authentications:maxkey-authentication-core")
|
||||
//local jars
|
||||
implementation fileTree(dir: '../maxkey-lib/', include: '*/*.jar')
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright [2022] [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.web.contorller;
|
||||
|
||||
public class ImageCaptcha {
|
||||
String id;
|
||||
String image;
|
||||
|
||||
public ImageCaptcha(String id, String image) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
public String getImage() {
|
||||
return image;
|
||||
}
|
||||
public void setImage(String image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* 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.web.contorller;
|
||||
|
||||
import com.google.code.kaptcha.Producer;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
|
||||
/**
|
||||
* ImageCaptchaEndpoint Producer captcha.
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
public class ImageCaptchaBase64Endpoint {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(ImageCaptchaBase64Endpoint.class);
|
||||
|
||||
public static final String IMAGE_GIF = "image/gif";
|
||||
|
||||
public static final String KAPTCHA_SESSION_KEY = "kaptcha_session_key";
|
||||
|
||||
@Autowired
|
||||
private Producer captchaProducer;
|
||||
|
||||
/**
|
||||
* captcha image Producer.
|
||||
*
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
*/
|
||||
@RequestMapping(value = "/captcha/base64")
|
||||
public void captchaHandleRequest(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@RequestParam(value="captcha",required=false,defaultValue="text") String captchaType) {
|
||||
try {
|
||||
|
||||
String kaptchaText = captchaProducer.createText();
|
||||
if (captchaType.equalsIgnoreCase("Arithmetic")) {
|
||||
Integer intParamA = Integer.valueOf(kaptchaText.substring(0, 1));
|
||||
Integer intParamB = Integer.valueOf(kaptchaText.substring(1, 2));
|
||||
Integer calculateValue = 0;
|
||||
if ((intParamA > intParamB) && ((intParamA + intParamB) % 5 > 3)) {
|
||||
calculateValue = intParamA - intParamB;
|
||||
kaptchaText = intParamA + "-" + intParamB + "=?";
|
||||
} else {
|
||||
calculateValue = intParamA + intParamB;
|
||||
kaptchaText = intParamA + "+" + intParamB + "=?";
|
||||
}
|
||||
_logger.trace("Sesssion id " + request.getSession().getId()
|
||||
+ " , Arithmetic calculate Value is " + calculateValue);
|
||||
request.getSession().setAttribute(
|
||||
KAPTCHA_SESSION_KEY, calculateValue + "");
|
||||
} else {
|
||||
// store the text in the session
|
||||
request.getSession().setAttribute(KAPTCHA_SESSION_KEY, kaptchaText);
|
||||
}
|
||||
_logger.trace("Sesssion id " + request.getSession().getId()
|
||||
+ " , Captcha Text is " + kaptchaText);
|
||||
|
||||
// create the image with the text
|
||||
BufferedImage bufferedImage = captchaProducer.createImage(kaptchaText);
|
||||
producerImage(request,response,bufferedImage);
|
||||
} catch (Exception e) {
|
||||
_logger.error("captcha Producer Error " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* producerImage.
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
* @param bufferedImage BufferedImage
|
||||
* @throws IOException error
|
||||
*/
|
||||
public static void producerImage(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
BufferedImage bufferedImage) throws IOException {
|
||||
// Set to expire far in the past.
|
||||
response.setDateHeader("Expires", 0);
|
||||
// Set standard HTTP/1.1 no-cache headers.
|
||||
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
||||
// Set IE extended HTTP/1.1 no-cache headers (use addHeader).
|
||||
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
|
||||
// Set standard HTTP/1.0 no-cache header.
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
// return a jpeg/gif
|
||||
//response.setContentType(IMAGE_GIF);
|
||||
_logger.trace("create the image");
|
||||
// create the image
|
||||
if (bufferedImage != null) {
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
// write the data out
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
ImageIO.write(bufferedImage, "png", stream);
|
||||
String b64Image = "data:image/png;base64," + Base64.getEncoder().encodeToString(stream.toByteArray());
|
||||
out.print(b64Image);
|
||||
_logger.debug("b64Image {}" , b64Image);
|
||||
stream.close();
|
||||
try {
|
||||
out.flush();
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setCaptchaProducer(Producer captchaProducer) {
|
||||
this.captchaProducer = captchaProducer;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
* Copyright [2022] [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.
|
||||
@ -18,16 +18,24 @@
|
||||
package org.maxkey.web.contorller;
|
||||
|
||||
import com.google.code.kaptcha.Producer;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.maxkey.authn.jwt.AuthJwtService;
|
||||
import org.maxkey.entity.Message;
|
||||
import org.maxkey.persistence.MomentaryService;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@ -42,88 +50,70 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
public class ImageCaptchaEndpoint {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(ImageCaptchaEndpoint.class);
|
||||
|
||||
public static final String IMAGE_GIF = "image/gif";
|
||||
|
||||
public static final String KAPTCHA_SESSION_KEY = "kaptcha_session_key";
|
||||
|
||||
@Autowired
|
||||
private Producer captchaProducer;
|
||||
|
||||
@Autowired
|
||||
protected MomentaryService momentaryService;
|
||||
|
||||
@Autowired
|
||||
AuthJwtService authJwtService;
|
||||
|
||||
/**
|
||||
* captcha image Producer.
|
||||
*
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
*/
|
||||
@RequestMapping(value = "/captcha")
|
||||
public void captchaHandleRequest(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@RequestParam(value="captcha",required=false,defaultValue="text") String captchaType) {
|
||||
@RequestMapping(value={"/captcha"}, produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
public ResponseEntity<?> captchaHandleRequest(
|
||||
@RequestParam(value="captcha",required=false,defaultValue="text") String captchaType,
|
||||
@RequestParam(value="state",required=false,defaultValue="state") String state) {
|
||||
try {
|
||||
|
||||
String kaptchaText = captchaProducer.createText();
|
||||
String kaptchaValue = kaptchaText;
|
||||
if (captchaType.equalsIgnoreCase("Arithmetic")) {
|
||||
Integer intParamA = Integer.valueOf(kaptchaText.substring(0, 1));
|
||||
Integer intParamB = Integer.valueOf(kaptchaText.substring(1, 2));
|
||||
Integer calculateValue = 0;
|
||||
if ((intParamA > intParamB) && ((intParamA + intParamB) % 5 > 3)) {
|
||||
calculateValue = intParamA - intParamB;
|
||||
kaptchaText = intParamA + "-" + intParamB + "=?";
|
||||
Integer minuend = Integer.valueOf(kaptchaText.substring(0, 1));
|
||||
Integer subtrahend = Integer.valueOf(kaptchaText.substring(1, 2));
|
||||
if (minuend - subtrahend > 0) {
|
||||
kaptchaValue = (minuend - subtrahend ) + "";
|
||||
kaptchaText = minuend + "-" + subtrahend + "=?";
|
||||
} else {
|
||||
calculateValue = intParamA + intParamB;
|
||||
kaptchaText = intParamA + "+" + intParamB + "=?";
|
||||
kaptchaValue = (minuend + subtrahend) + "";
|
||||
kaptchaText = minuend + "+" + subtrahend + "=?";
|
||||
}
|
||||
_logger.trace("Sesssion id " + request.getSession().getId()
|
||||
+ " , Arithmetic calculate Value is " + calculateValue);
|
||||
request.getSession().setAttribute(
|
||||
KAPTCHA_SESSION_KEY, calculateValue + "");
|
||||
}
|
||||
String kaptchaKey = "";
|
||||
if(StringUtils.isNotBlank(state)
|
||||
&& !state.equalsIgnoreCase("state")
|
||||
&& authJwtService.validateJwtToken(state)) {
|
||||
JWTClaimsSet claim = authJwtService.resolve(state);
|
||||
kaptchaKey = claim.getJWTID();
|
||||
}else {
|
||||
// store the text in the session
|
||||
request.getSession().setAttribute(KAPTCHA_SESSION_KEY, kaptchaText);
|
||||
kaptchaKey = WebContext.genId();
|
||||
}
|
||||
_logger.trace("Sesssion id " + request.getSession().getId()
|
||||
+ " , Captcha Text is " + kaptchaText);
|
||||
_logger.trace("kaptchaKey {} , Captcha Text is {}" ,kaptchaKey, kaptchaValue);
|
||||
|
||||
momentaryService.put("", kaptchaKey, kaptchaValue);
|
||||
// create the image with the text
|
||||
BufferedImage bufferedImage = captchaProducer.createImage(kaptchaText);
|
||||
producerImage(request,response,bufferedImage);
|
||||
// write the data out
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
ImageIO.write(bufferedImage, "png", stream);
|
||||
|
||||
String b64Image = "data:image/png;base64," +
|
||||
Base64.getEncoder().encodeToString(stream.toByteArray());
|
||||
|
||||
_logger.trace("b64Image {}" , b64Image);
|
||||
|
||||
stream.close();
|
||||
return new Message<ImageCaptcha>(
|
||||
new ImageCaptcha(kaptchaKey,b64Image)
|
||||
).buildResponse();
|
||||
} catch (Exception e) {
|
||||
_logger.error("captcha Producer Error " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* producerImage.
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
* @param bufferedImage BufferedImage
|
||||
* @throws IOException error
|
||||
*/
|
||||
public static void producerImage(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
BufferedImage bufferedImage) throws IOException {
|
||||
// Set to expire far in the past.
|
||||
response.setDateHeader("Expires", 0);
|
||||
// Set standard HTTP/1.1 no-cache headers.
|
||||
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
||||
// Set IE extended HTTP/1.1 no-cache headers (use addHeader).
|
||||
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
|
||||
// Set standard HTTP/1.0 no-cache header.
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
// return a jpeg/gif
|
||||
response.setContentType(IMAGE_GIF);
|
||||
_logger.trace("create the image");
|
||||
// create the image
|
||||
if (bufferedImage != null) {
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
// write the data out
|
||||
ImageIO.write(bufferedImage, "gif", out);
|
||||
try {
|
||||
out.flush();
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
return new Message< Object>(Message.FAIL).buildResponse();
|
||||
}
|
||||
|
||||
public void setCaptchaProducer(Producer captchaProducer) {
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
kaptcha.image.width=80
|
||||
kaptcha.image.height=40
|
||||
kaptcha.border=no
|
||||
kaptcha.obscurificator.impl=com.google.code.kaptcha.impl.ShadowGimpy
|
||||
#kaptcha.obscurificator.impl=com.google.code.kaptcha.impl.ShadowGimpy
|
||||
kaptcha.obscurificator.impl=com.google.code.kaptcha.impl.Ripple
|
||||
kaptcha.textproducer.font.size=23
|
||||
kaptcha.textproducer.char.string=0123456789
|
||||
kaptcha.textproducer.char.length=4
|
||||
kaptcha.noise.impl=com.google.code.kaptcha.impl.NoNoise
|
||||
kaptcha.textproducer.char.space=3
|
||||
#kaptcha.noise.impl=com.google.code.kaptcha.impl.DefaultNoise
|
||||
kaptcha.noise.impl=com.google.code.kaptcha.impl.LightNoise
|
||||
#kaptcha.noise.color=white
|
||||
kaptcha.word.impl=com.google.code.kaptcha.text.impl.RandomColorWordRenderer
|
||||
@ -0,0 +1,9 @@
|
||||
kaptcha.image.width=80
|
||||
kaptcha.image.height=40
|
||||
kaptcha.border=no
|
||||
kaptcha.obscurificator.impl=com.google.code.kaptcha.impl.ShadowGimpy
|
||||
kaptcha.textproducer.font.size=23
|
||||
kaptcha.textproducer.char.string=0123456789
|
||||
kaptcha.textproducer.char.length=4
|
||||
kaptcha.noise.impl=com.google.code.kaptcha.impl.NoNoise
|
||||
#kaptcha.noise.color=white
|
||||
@ -20,6 +20,7 @@ package org.maxkey.authn;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.maxkey.authn.jwt.AuthJwtService;
|
||||
import org.maxkey.authn.online.OnlineTicketService;
|
||||
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
|
||||
import org.maxkey.configuration.ApplicationConfig;
|
||||
@ -28,6 +29,7 @@ import org.maxkey.constants.ConstsStatus;
|
||||
import org.maxkey.entity.UserInfo;
|
||||
import org.maxkey.password.onetimepwd.AbstractOtpAuthn;
|
||||
import org.maxkey.password.onetimepwd.OtpAuthnService;
|
||||
import org.maxkey.persistence.MomentaryService;
|
||||
import org.maxkey.web.WebConstants;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
@ -51,7 +53,14 @@ public abstract class AbstractAuthenticationProvider {
|
||||
public final static String NORMAL = "normal";
|
||||
public final static String TFA = "tfa";
|
||||
public final static String MOBILE = "mobile";
|
||||
public final static String TRUSTED = "trusted";
|
||||
}
|
||||
|
||||
protected static String PROVIDER_SUFFIX = "AuthenticationProvider";
|
||||
|
||||
private static HashMap<String,AbstractAuthenticationProvider> providers =
|
||||
new HashMap<String,AbstractAuthenticationProvider>();
|
||||
|
||||
protected ApplicationConfig applicationConfig;
|
||||
|
||||
protected AbstractAuthenticationRealm authenticationRealm;
|
||||
@ -62,87 +71,42 @@ public abstract class AbstractAuthenticationProvider {
|
||||
|
||||
protected OnlineTicketService onlineTicketServices;
|
||||
|
||||
protected MomentaryService momentaryService;
|
||||
|
||||
protected AuthJwtService authJwtService;
|
||||
|
||||
public static ArrayList<GrantedAuthority> grantedAdministratorsAuthoritys = new ArrayList<GrantedAuthority>();
|
||||
|
||||
static {
|
||||
grantedAdministratorsAuthoritys.add(new SimpleGrantedAuthority("ROLE_ADMINISTRATORS"));
|
||||
}
|
||||
|
||||
protected abstract String getProviderName();
|
||||
public abstract String getProviderName();
|
||||
|
||||
public abstract Authentication authenticate(LoginCredential authentication);
|
||||
|
||||
public abstract Authentication authentication(LoginCredential loginCredential,boolean isTrusted);
|
||||
public abstract Authentication doAuthenticate(LoginCredential authentication);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public boolean supports(Class authentication) {
|
||||
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
|
||||
}
|
||||
|
||||
protected void changeSession(Authentication authentication) {
|
||||
public Authentication authenticate(LoginCredential authentication){
|
||||
if(authentication.getAuthType().equalsIgnoreCase("trusted")) {
|
||||
return null;
|
||||
}
|
||||
AbstractAuthenticationProvider provider = providers.get(authentication.getAuthType() + PROVIDER_SUFFIX);
|
||||
|
||||
HashMap<String,Object> sessionAttributeMap = new HashMap<String,Object>();
|
||||
for(String attributeName : WebContext.sessionAttributeNameList) {
|
||||
sessionAttributeMap.put(attributeName, WebContext.getAttribute(attributeName));
|
||||
WebContext.removeAttribute(attributeName);
|
||||
return provider == null ? null : provider.doAuthenticate(authentication);
|
||||
}
|
||||
|
||||
//new Session
|
||||
WebContext.getSession().invalidate();
|
||||
|
||||
for(String attributeName : WebContext.sessionAttributeNameList) {
|
||||
WebContext.setAttribute(attributeName, sessionAttributeMap.get(attributeName));
|
||||
}
|
||||
public Authentication authenticate(LoginCredential authentication,boolean trusted){
|
||||
AbstractAuthenticationProvider provider = providers.get(AuthType.TRUSTED + PROVIDER_SUFFIX);
|
||||
return provider == null ? null : provider.doAuthenticate(authentication);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
public void addAuthenticationProvider(AbstractAuthenticationProvider provider) {
|
||||
providers.put(provider.getProviderName(), provider);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(AuthType.NORMAL)
|
||||
|| authType.equalsIgnoreCase(AuthType.TFA)
|
||||
|| authType.equalsIgnoreCase(AuthType.MOBILE)
|
||||
)
|
||||
) {
|
||||
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 .
|
||||
*
|
||||
@ -189,28 +153,7 @@ public abstract class AbstractAuthenticationProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mobile validate.
|
||||
*
|
||||
* @param otpCaptcha String
|
||||
* @param authType String
|
||||
* @param userInfo UserInfo
|
||||
*/
|
||||
protected void mobilecaptchaValid(String password, String authType, UserInfo userInfo) {
|
||||
// for mobile password
|
||||
if (applicationConfig.getLoginConfig().isMfa()
|
||||
&& authType.equalsIgnoreCase(AuthType.MOBILE)) {
|
||||
UserInfo validUserInfo = new UserInfo();
|
||||
validUserInfo.setUsername(userInfo.getUsername());
|
||||
validUserInfo.setId(userInfo.getId());
|
||||
AbstractOtpAuthn smsOtpAuthn = otpAuthnService.getByInstId(userInfo.getInstId());
|
||||
if (password == null || !smsOtpAuthn.validate(validUserInfo, password)) {
|
||||
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
|
||||
|
||||
@ -33,7 +33,7 @@ public class LoginCredential implements Authentication {
|
||||
String congress;
|
||||
String username;
|
||||
String password;
|
||||
String sessionId;
|
||||
String state;
|
||||
String captcha;
|
||||
String otpCaptcha;
|
||||
String remeberMe;
|
||||
@ -126,12 +126,12 @@ public class LoginCredential implements Authentication {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return sessionId;
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setSessionId(String sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getCaptcha() {
|
||||
@ -233,12 +233,14 @@ public class LoginCredential implements Authentication {
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("LoginCredential [username=");
|
||||
builder.append("LoginCredential [congress=");
|
||||
builder.append(congress);
|
||||
builder.append(", username=");
|
||||
builder.append(username);
|
||||
builder.append(", password=");
|
||||
builder.append("******");
|
||||
builder.append(", sessionId=");
|
||||
builder.append(sessionId);
|
||||
builder.append(password);
|
||||
builder.append(", state=");
|
||||
builder.append(state);
|
||||
builder.append(", captcha=");
|
||||
builder.append(captcha);
|
||||
builder.append(", otpCaptcha=");
|
||||
|
||||
@ -15,10 +15,14 @@
|
||||
*/
|
||||
|
||||
|
||||
package org.maxkey.authn;
|
||||
package org.maxkey.authn.provider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.maxkey.authn.AbstractAuthenticationProvider;
|
||||
import org.maxkey.authn.LoginCredential;
|
||||
import org.maxkey.authn.SigninPrincipal;
|
||||
import org.maxkey.authn.jwt.AuthJwtService;
|
||||
import org.maxkey.authn.online.OnlineTicket;
|
||||
import org.maxkey.authn.online.OnlineTicketService;
|
||||
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
|
||||
@ -27,13 +31,11 @@ import org.maxkey.configuration.ApplicationConfig;
|
||||
import org.maxkey.constants.ConstsLoginType;
|
||||
import org.maxkey.entity.Institutions;
|
||||
import org.maxkey.entity.UserInfo;
|
||||
import org.maxkey.password.onetimepwd.AbstractOtpAuthn;
|
||||
import org.maxkey.password.onetimepwd.OtpAuthnService;
|
||||
import org.maxkey.persistence.MomentaryService;
|
||||
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.AuthenticationException;
|
||||
@ -46,35 +48,34 @@ import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class RealmAuthenticationProvider extends AbstractAuthenticationProvider {
|
||||
public class MfaAuthenticationProvider extends AbstractAuthenticationProvider {
|
||||
private static final Logger _logger =
|
||||
LoggerFactory.getLogger(RealmAuthenticationProvider.class);
|
||||
LoggerFactory.getLogger(MfaAuthenticationProvider.class);
|
||||
|
||||
protected String getProviderName() {
|
||||
return "RealmAuthenticationProvider";
|
||||
public String getProviderName() {
|
||||
return "normal" + PROVIDER_SUFFIX;
|
||||
}
|
||||
|
||||
|
||||
public RealmAuthenticationProvider() {
|
||||
public MfaAuthenticationProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
public RealmAuthenticationProvider(
|
||||
public MfaAuthenticationProvider(
|
||||
AbstractAuthenticationRealm authenticationRealm,
|
||||
ApplicationConfig applicationConfig,
|
||||
AbstractOtpAuthn tfaOtpAuthn,
|
||||
OtpAuthnService otpAuthnService,
|
||||
OnlineTicketService onlineTicketServices) {
|
||||
OnlineTicketService onlineTicketServices,
|
||||
AuthJwtService authJwtService,
|
||||
MomentaryService momentaryService) {
|
||||
this.authenticationRealm = authenticationRealm;
|
||||
this.applicationConfig = applicationConfig;
|
||||
this.tfaOtpAuthn = tfaOtpAuthn;
|
||||
this.otpAuthnService = otpAuthnService;
|
||||
this.onlineTicketServices = onlineTicketServices;
|
||||
this.authJwtService = authJwtService;
|
||||
this.momentaryService = momentaryService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(LoginCredential loginCredential) {
|
||||
public Authentication doAuthenticate(LoginCredential loginCredential) {
|
||||
UsernamePasswordAuthenticationToken authenticationToken = null;
|
||||
_logger.debug("Trying to authenticate user '{}' via {}",
|
||||
loginCredential.getPrincipal(), getProviderName());
|
||||
@ -82,12 +83,6 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
|
||||
|
||||
_logger.debug("authentication " + loginCredential);
|
||||
|
||||
//sessionValid(loginCredential.getSessionId());
|
||||
|
||||
//jwtTokenValid(j_jwtToken);
|
||||
|
||||
authTypeValid(loginCredential.getAuthType());
|
||||
|
||||
Institutions inst = (Institutions)WebContext.getAttribute(WebConstants.CURRENT_INST);
|
||||
if(inst.getCaptchaSupport().equalsIgnoreCase("YES")) {
|
||||
captchaValid(loginCredential.getCaptcha(),loginCredential.getAuthType());
|
||||
@ -107,12 +102,10 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
|
||||
|
||||
//Validate PasswordPolicy
|
||||
authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(userInfo);
|
||||
if(loginCredential.getAuthType().equalsIgnoreCase(AuthType.MOBILE)) {
|
||||
mobilecaptchaValid(loginCredential.getPassword(),loginCredential.getAuthType(),userInfo);
|
||||
}else {
|
||||
|
||||
//Match password
|
||||
authenticationRealm.passwordMatches(userInfo, loginCredential.getPassword());
|
||||
}
|
||||
|
||||
//apply PasswordSetType and resetBadPasswordCount
|
||||
authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(userInfo);
|
||||
|
||||
@ -121,8 +114,6 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
|
||||
_logger.debug("'{}' authenticated successfully by {}.",
|
||||
loginCredential.getPrincipal(), getProviderName());
|
||||
|
||||
changeSession(authenticationToken);
|
||||
|
||||
authenticationRealm.insertLoginHistory(userInfo,
|
||||
ConstsLoginType.LOCAL,
|
||||
"",
|
||||
@ -143,46 +134,6 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* trustAuthentication.
|
||||
* @param username String
|
||||
* @param type String
|
||||
* @param provider String
|
||||
* @param code String
|
||||
* @param message String
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public Authentication authentication(LoginCredential loginCredential,boolean isTrusted) {
|
||||
UserInfo loadeduserInfo = loadUserInfo(loginCredential.getUsername(), "");
|
||||
statusValid(loginCredential , loadeduserInfo);
|
||||
if (loadeduserInfo != null) {
|
||||
|
||||
//Validate PasswordPolicy
|
||||
authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(loadeduserInfo);
|
||||
if(!isTrusted) {
|
||||
authenticationRealm.passwordMatches(loadeduserInfo, loginCredential.getPassword());
|
||||
}
|
||||
//apply PasswordSetType and resetBadPasswordCount
|
||||
authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(loadeduserInfo);
|
||||
Authentication authentication = createOnlineSession(loginCredential,loadeduserInfo);
|
||||
|
||||
authenticationRealm.insertLoginHistory( loadeduserInfo,
|
||||
loginCredential.getAuthType(),
|
||||
loginCredential.getProvider(),
|
||||
loginCredential.getCode(),
|
||||
loginCredential.getMessage()
|
||||
);
|
||||
|
||||
return authentication;
|
||||
}else {
|
||||
String i18nMessage = WebContext.getI18nValue("login.error.username");
|
||||
_logger.debug("login user {} not in this System . {}" ,
|
||||
loginCredential.getUsername(),i18nMessage);
|
||||
throw new BadCredentialsException(WebContext.getI18nValue("login.error.username"));
|
||||
}
|
||||
}
|
||||
|
||||
public UsernamePasswordAuthenticationToken createOnlineSession(LoginCredential credential,UserInfo userInfo) {
|
||||
//Online Tickit
|
||||
OnlineTicket onlineTicket = new OnlineTicket();
|
||||
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright [2022] [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.provider;
|
||||
|
||||
import org.maxkey.authn.LoginCredential;
|
||||
import org.maxkey.authn.online.OnlineTicketService;
|
||||
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
|
||||
import org.maxkey.configuration.ApplicationConfig;
|
||||
import org.maxkey.constants.ConstsLoginType;
|
||||
import org.maxkey.entity.UserInfo;
|
||||
import org.maxkey.password.onetimepwd.AbstractOtpAuthn;
|
||||
import org.maxkey.password.onetimepwd.OtpAuthnService;
|
||||
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.AuthenticationException;
|
||||
|
||||
|
||||
/**
|
||||
* Mobile Authentication provider.
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class MobileAuthenticationProvider extends NormalAuthenticationProvider {
|
||||
|
||||
private static final Logger _logger =
|
||||
LoggerFactory.getLogger(MobileAuthenticationProvider.class);
|
||||
|
||||
public String getProviderName() {
|
||||
return "mobile" + PROVIDER_SUFFIX;
|
||||
}
|
||||
|
||||
|
||||
public MobileAuthenticationProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
public MobileAuthenticationProvider(
|
||||
AbstractAuthenticationRealm authenticationRealm,
|
||||
ApplicationConfig applicationConfig,
|
||||
OtpAuthnService otpAuthnService,
|
||||
OnlineTicketService onlineTicketServices) {
|
||||
this.authenticationRealm = authenticationRealm;
|
||||
this.applicationConfig = applicationConfig;
|
||||
this.otpAuthnService = otpAuthnService;
|
||||
this.onlineTicketServices = onlineTicketServices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(LoginCredential loginCredential) {
|
||||
UsernamePasswordAuthenticationToken authenticationToken = null;
|
||||
_logger.debug("Trying to authenticate user '{}' via {}",
|
||||
loginCredential.getPrincipal(), getProviderName());
|
||||
try {
|
||||
|
||||
_logger.debug("authentication " + loginCredential);
|
||||
|
||||
emptyPasswordValid(loginCredential.getPassword());
|
||||
|
||||
emptyUsernameValid(loginCredential.getUsername());
|
||||
|
||||
UserInfo userInfo = loadUserInfo(loginCredential.getUsername(),loginCredential.getPassword());
|
||||
|
||||
statusValid(loginCredential , userInfo);
|
||||
|
||||
//Validate PasswordPolicy
|
||||
authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(userInfo);
|
||||
|
||||
mobilecaptchaValid(loginCredential.getPassword(),userInfo);
|
||||
|
||||
//apply PasswordSetType and resetBadPasswordCount
|
||||
authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(userInfo);
|
||||
|
||||
authenticationToken = createOnlineSession(loginCredential,userInfo);
|
||||
// user authenticated
|
||||
_logger.debug("'{}' authenticated successfully by {}.",
|
||||
loginCredential.getPrincipal(), getProviderName());
|
||||
|
||||
authenticationRealm.insertLoginHistory(userInfo,
|
||||
ConstsLoginType.LOCAL,
|
||||
"",
|
||||
"xe00000004",
|
||||
WebConstants.LOGIN_RESULT.SUCCESS);
|
||||
} 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) {
|
||||
_logger.error("Login error Unexpected exception in {} authentication:\n{}" ,
|
||||
getProviderName(), e.getMessage());
|
||||
}
|
||||
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mobile validate.
|
||||
*
|
||||
* @param otpCaptcha String
|
||||
* @param authType String
|
||||
* @param userInfo UserInfo
|
||||
*/
|
||||
protected void mobilecaptchaValid(String password, UserInfo userInfo) {
|
||||
// for mobile password
|
||||
if (applicationConfig.getLoginConfig().isMfa()) {
|
||||
UserInfo validUserInfo = new UserInfo();
|
||||
validUserInfo.setUsername(userInfo.getUsername());
|
||||
validUserInfo.setId(userInfo.getId());
|
||||
AbstractOtpAuthn smsOtpAuthn = otpAuthnService.getByInstId(userInfo.getInstId());
|
||||
if (password == null || !smsOtpAuthn.validate(validUserInfo, password)) {
|
||||
String message = WebContext.getI18nValue("login.error.captcha");
|
||||
_logger.debug("login captcha valid error.");
|
||||
throw new BadCredentialsException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright [2022] [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.provider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.maxkey.authn.AbstractAuthenticationProvider;
|
||||
import org.maxkey.authn.LoginCredential;
|
||||
import org.maxkey.authn.SigninPrincipal;
|
||||
import org.maxkey.authn.jwt.AuthJwtService;
|
||||
import org.maxkey.authn.online.OnlineTicket;
|
||||
import org.maxkey.authn.online.OnlineTicketService;
|
||||
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
|
||||
import org.maxkey.authn.web.AuthorizationUtils;
|
||||
import org.maxkey.configuration.ApplicationConfig;
|
||||
import org.maxkey.constants.ConstsLoginType;
|
||||
import org.maxkey.entity.Institutions;
|
||||
import org.maxkey.entity.UserInfo;
|
||||
import org.maxkey.persistence.MomentaryService;
|
||||
import org.maxkey.web.WebConstants;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.web.authentication.WebAuthenticationDetails;
|
||||
|
||||
|
||||
/**
|
||||
* database Authentication provider.
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class NormalAuthenticationProvider extends AbstractAuthenticationProvider {
|
||||
private static final Logger _logger =
|
||||
LoggerFactory.getLogger(NormalAuthenticationProvider.class);
|
||||
|
||||
public String getProviderName() {
|
||||
return "normal" + PROVIDER_SUFFIX;
|
||||
}
|
||||
|
||||
|
||||
public NormalAuthenticationProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NormalAuthenticationProvider(
|
||||
AbstractAuthenticationRealm authenticationRealm,
|
||||
ApplicationConfig applicationConfig,
|
||||
OnlineTicketService onlineTicketServices,
|
||||
AuthJwtService authJwtService,
|
||||
MomentaryService momentaryService) {
|
||||
this.authenticationRealm = authenticationRealm;
|
||||
this.applicationConfig = applicationConfig;
|
||||
this.onlineTicketServices = onlineTicketServices;
|
||||
this.authJwtService = authJwtService;
|
||||
this.momentaryService = momentaryService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication doAuthenticate(LoginCredential loginCredential) {
|
||||
UsernamePasswordAuthenticationToken authenticationToken = null;
|
||||
_logger.debug("Trying to authenticate user '{}' via {}",
|
||||
loginCredential.getPrincipal(), getProviderName());
|
||||
try {
|
||||
|
||||
_logger.debug("authentication " + loginCredential);
|
||||
|
||||
Institutions inst = (Institutions)WebContext.getAttribute(WebConstants.CURRENT_INST);
|
||||
if(inst.getCaptchaSupport().equalsIgnoreCase("YES")) {
|
||||
captchaValid(loginCredential.getCaptcha(),loginCredential.getAuthType());
|
||||
}
|
||||
|
||||
emptyPasswordValid(loginCredential.getPassword());
|
||||
|
||||
emptyUsernameValid(loginCredential.getUsername());
|
||||
|
||||
UserInfo userInfo = loadUserInfo(loginCredential.getUsername(),loginCredential.getPassword());
|
||||
|
||||
statusValid(loginCredential , userInfo);
|
||||
|
||||
//Validate PasswordPolicy
|
||||
authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(userInfo);
|
||||
|
||||
//Match password
|
||||
authenticationRealm.passwordMatches(userInfo, loginCredential.getPassword());
|
||||
|
||||
//apply PasswordSetType and resetBadPasswordCount
|
||||
authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(userInfo);
|
||||
|
||||
authenticationToken = createOnlineSession(loginCredential,userInfo);
|
||||
// user authenticated
|
||||
_logger.debug("'{}' authenticated successfully by {}.",
|
||||
loginCredential.getPrincipal(), getProviderName());
|
||||
|
||||
authenticationRealm.insertLoginHistory(userInfo,
|
||||
ConstsLoginType.LOCAL,
|
||||
"",
|
||||
"xe00000004",
|
||||
WebConstants.LOGIN_RESULT.SUCCESS);
|
||||
} 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) {
|
||||
_logger.error("Login error Unexpected exception in {} authentication:\n{}" ,
|
||||
getProviderName(), e.getMessage());
|
||||
}
|
||||
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
public UsernamePasswordAuthenticationToken createOnlineSession(LoginCredential credential,UserInfo userInfo) {
|
||||
//Online Tickit
|
||||
OnlineTicket onlineTicket = new OnlineTicket();
|
||||
|
||||
userInfo.setOnlineTicket(onlineTicket.getTicketId());
|
||||
|
||||
SigninPrincipal principal = new SigninPrincipal(userInfo);
|
||||
//set OnlineTicket
|
||||
principal.setOnlineTicket(onlineTicket);
|
||||
ArrayList<GrantedAuthority> grantedAuthoritys = authenticationRealm.grantAuthority(userInfo);
|
||||
principal.setAuthenticated(true);
|
||||
|
||||
for(GrantedAuthority administratorsAuthority : grantedAdministratorsAuthoritys) {
|
||||
if(grantedAuthoritys.contains(administratorsAuthority)) {
|
||||
principal.setRoleAdministrators(true);
|
||||
_logger.trace("ROLE ADMINISTRATORS Authentication .");
|
||||
}
|
||||
}
|
||||
_logger.debug("Granted Authority {}" , grantedAuthoritys);
|
||||
|
||||
principal.setGrantedAuthorityApps(authenticationRealm.queryAuthorizedApps(grantedAuthoritys));
|
||||
|
||||
UsernamePasswordAuthenticationToken authenticationToken =
|
||||
new UsernamePasswordAuthenticationToken(
|
||||
principal,
|
||||
"PASSWORD",
|
||||
grantedAuthoritys
|
||||
);
|
||||
|
||||
authenticationToken.setDetails(
|
||||
new WebAuthenticationDetails(WebContext.getRequest()));
|
||||
|
||||
onlineTicket.setAuthentication(authenticationToken);
|
||||
|
||||
//store onlineTicket
|
||||
this.onlineTicketServices.store(onlineTicket.getTicketId(), onlineTicket);
|
||||
|
||||
/*
|
||||
* put Authentication to current session context
|
||||
*/
|
||||
AuthorizationUtils.setAuthentication(authenticationToken);
|
||||
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright [2022] [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.provider;
|
||||
|
||||
import org.maxkey.authn.LoginCredential;
|
||||
import org.maxkey.authn.online.OnlineTicketService;
|
||||
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
|
||||
import org.maxkey.configuration.ApplicationConfig;
|
||||
import org.maxkey.entity.UserInfo;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* Trusted Authentication provider.
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
public class TrustedAuthenticationProvider extends NormalAuthenticationProvider {
|
||||
private static final Logger _logger =
|
||||
LoggerFactory.getLogger(TrustedAuthenticationProvider.class);
|
||||
|
||||
public String getProviderName() {
|
||||
return "trusted" + PROVIDER_SUFFIX;
|
||||
}
|
||||
|
||||
public TrustedAuthenticationProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TrustedAuthenticationProvider(
|
||||
AbstractAuthenticationRealm authenticationRealm,
|
||||
ApplicationConfig applicationConfig,
|
||||
OnlineTicketService onlineTicketServices) {
|
||||
this.authenticationRealm = authenticationRealm;
|
||||
this.applicationConfig = applicationConfig;
|
||||
this.onlineTicketServices = onlineTicketServices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication doAuthenticate(LoginCredential loginCredential) {
|
||||
UserInfo loadeduserInfo = loadUserInfo(loginCredential.getUsername(), "");
|
||||
statusValid(loginCredential , loadeduserInfo);
|
||||
if (loadeduserInfo != null) {
|
||||
//Validate PasswordPolicy
|
||||
authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(loadeduserInfo);
|
||||
//apply PasswordSetType and resetBadPasswordCount
|
||||
authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(loadeduserInfo);
|
||||
Authentication authentication = createOnlineSession(loginCredential,loadeduserInfo);
|
||||
|
||||
authenticationRealm.insertLoginHistory( loadeduserInfo,
|
||||
loginCredential.getAuthType(),
|
||||
loginCredential.getProvider(),
|
||||
loginCredential.getCode(),
|
||||
loginCredential.getMessage()
|
||||
);
|
||||
|
||||
return authentication;
|
||||
}else {
|
||||
String i18nMessage = WebContext.getI18nValue("login.error.username");
|
||||
_logger.debug("login user {} not in this System . {}" ,
|
||||
loginCredential.getUsername(),i18nMessage);
|
||||
throw new BadCredentialsException(WebContext.getI18nValue("login.error.username"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
package org.maxkey.authn.provider;
|
||||
@ -131,7 +131,7 @@ public class BasicEntryPoint implements AsyncHandlerInterceptor {
|
||||
|
||||
if(!isAuthenticated){
|
||||
LoginCredential loginCredential =new LoginCredential(headerCredential.getUsername(),"",ConstsLoginType.BASIC);
|
||||
authenticationProvider.authentication(loginCredential,true);
|
||||
authenticationProvider.authenticate(loginCredential,true);
|
||||
_logger.info("Authentication "+headerCredential.getUsername()+" successful .");
|
||||
}
|
||||
|
||||
|
||||
@ -110,7 +110,7 @@ public class HttpHeaderEntryPoint implements AsyncHandlerInterceptor {
|
||||
|
||||
if(!isAuthenticated){
|
||||
LoginCredential loginCredential =new LoginCredential(httpHeaderUsername,"",ConstsLoginType.HTTPHEADER);
|
||||
authenticationProvider.authentication(loginCredential,true);
|
||||
authenticationProvider.authenticate(loginCredential,true);
|
||||
_logger.info("Authentication "+httpHeaderUsername+" successful .");
|
||||
}
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ public class HttpJwtEntryPoint implements AsyncHandlerInterceptor {
|
||||
if(signedJWT != null) {
|
||||
String username =signedJWT.getJWTClaimsSet().getSubject();
|
||||
LoginCredential loginCredential =new LoginCredential(username,"",ConstsLoginType.JWT);
|
||||
authenticationProvider.authentication(loginCredential,true);
|
||||
authenticationProvider.authenticate(loginCredential,true);
|
||||
_logger.debug("JWT Logined in , username " + username);
|
||||
}
|
||||
|
||||
|
||||
@ -97,7 +97,7 @@ public class HttpKerberosEntryPoint implements AsyncHandlerInterceptor {
|
||||
if(notOnOrAfter.isAfterNow()){
|
||||
LoginCredential loginCredential =new LoginCredential(kerberosToken.getPrincipal(),"",ConstsLoginType.KERBEROS);
|
||||
loginCredential.setProvider(kerberosUserDomain);
|
||||
authenticationProvider.authentication(loginCredential,true);
|
||||
authenticationProvider.authenticate(loginCredential,true);
|
||||
_logger.debug("Kerberos Logined in , username " + kerberosToken.getPrincipal());
|
||||
}
|
||||
|
||||
|
||||
@ -100,7 +100,7 @@ public class HttpWsFederationEntryPoint implements AsyncHandlerInterceptor {
|
||||
}
|
||||
LoginCredential loginCredential =new LoginCredential(
|
||||
wsFederationCredential.getAttributes().get("").toString(),"",ConstsLoginType.WSFEDERATION);
|
||||
authenticationProvider.authentication(loginCredential,true);
|
||||
authenticationProvider.authenticate(loginCredential,true);
|
||||
return true;
|
||||
} else {
|
||||
_logger.warn("SAML assertions are blank or no longer valid.");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
* Copyright [2022] [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.
|
||||
@ -18,7 +18,6 @@
|
||||
package org.maxkey.autoconfigure;
|
||||
|
||||
import org.maxkey.authn.AbstractAuthenticationProvider;
|
||||
import org.maxkey.authn.RealmAuthenticationProvider;
|
||||
import org.maxkey.authn.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.maxkey.authn.jwt.AuthJwtService;
|
||||
import org.maxkey.authn.jwt.CongressService;
|
||||
@ -26,6 +25,9 @@ import org.maxkey.authn.jwt.InMemoryCongressService;
|
||||
import org.maxkey.authn.jwt.RedisCongressService;
|
||||
import org.maxkey.authn.online.OnlineTicketService;
|
||||
import org.maxkey.authn.online.OnlineTicketServiceFactory;
|
||||
import org.maxkey.authn.provider.MobileAuthenticationProvider;
|
||||
import org.maxkey.authn.provider.NormalAuthenticationProvider;
|
||||
import org.maxkey.authn.provider.TrustedAuthenticationProvider;
|
||||
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
|
||||
import org.maxkey.authn.web.SessionListenerAdapter;
|
||||
import org.maxkey.configuration.ApplicationConfig;
|
||||
@ -34,6 +36,7 @@ import org.maxkey.constants.ConstsPersistence;
|
||||
import org.maxkey.password.onetimepwd.AbstractOtpAuthn;
|
||||
import org.maxkey.password.onetimepwd.OtpAuthnService;
|
||||
import org.maxkey.password.onetimepwd.token.RedisOtpTokenStore;
|
||||
import org.maxkey.persistence.MomentaryService;
|
||||
import org.maxkey.persistence.redis.RedisConnectionFactory;
|
||||
import org.maxkey.persistence.repository.LoginHistoryRepository;
|
||||
import org.maxkey.persistence.repository.LoginRepository;
|
||||
@ -68,20 +71,61 @@ public class AuthenticationAutoConfiguration implements InitializingBean {
|
||||
public AbstractAuthenticationProvider authenticationProvider(
|
||||
AbstractAuthenticationRealm authenticationRealm,
|
||||
ApplicationConfig applicationConfig,
|
||||
AbstractOtpAuthn tfaOtpAuthn,
|
||||
OtpAuthnService otpAuthnService,
|
||||
OnlineTicketService onlineTicketServices
|
||||
OnlineTicketService onlineTicketServices,
|
||||
AuthJwtService authJwtService,
|
||||
MomentaryService momentaryService
|
||||
) {
|
||||
|
||||
_logger.debug("init authentication Provider .");
|
||||
return new RealmAuthenticationProvider(
|
||||
NormalAuthenticationProvider normal = new NormalAuthenticationProvider(
|
||||
authenticationRealm,
|
||||
applicationConfig,
|
||||
onlineTicketServices,
|
||||
authJwtService,
|
||||
momentaryService
|
||||
);
|
||||
|
||||
normal.addAuthenticationProvider(normal);
|
||||
return normal;
|
||||
}
|
||||
|
||||
@Bean(name = "mobileAuthenticationProvider")
|
||||
public AbstractAuthenticationProvider mobileAuthenticationProvider(
|
||||
AbstractAuthenticationRealm authenticationRealm,
|
||||
ApplicationConfig applicationConfig,
|
||||
OtpAuthnService otpAuthnService,
|
||||
OnlineTicketService onlineTicketServices,
|
||||
AbstractAuthenticationProvider authenticationProvider
|
||||
) {
|
||||
MobileAuthenticationProvider mobile = new MobileAuthenticationProvider(
|
||||
authenticationRealm,
|
||||
applicationConfig,
|
||||
tfaOtpAuthn,
|
||||
otpAuthnService,
|
||||
onlineTicketServices
|
||||
);
|
||||
|
||||
authenticationProvider.addAuthenticationProvider(mobile);
|
||||
_logger.debug("init Mobile authentication Provider .");
|
||||
return mobile;
|
||||
}
|
||||
|
||||
|
||||
@Bean(name = "trustedAuthenticationProvider")
|
||||
public AbstractAuthenticationProvider trustedAuthenticationProvider(
|
||||
AbstractAuthenticationRealm authenticationRealm,
|
||||
ApplicationConfig applicationConfig,
|
||||
OnlineTicketService onlineTicketServices,
|
||||
AbstractAuthenticationProvider authenticationProvider
|
||||
) {
|
||||
TrustedAuthenticationProvider trusted = new TrustedAuthenticationProvider(
|
||||
authenticationRealm,
|
||||
applicationConfig,
|
||||
onlineTicketServices
|
||||
);
|
||||
|
||||
authenticationProvider.addAuthenticationProvider(trusted);
|
||||
_logger.debug("init Mobile authentication Provider .");
|
||||
return trusted;
|
||||
}
|
||||
|
||||
@Bean(name = "authJwtService")
|
||||
|
||||
@ -133,7 +133,7 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
|
||||
SocialsProvider socialSignOnProvider = socialSignOnProviderService.get(instId,provider);
|
||||
loginCredential.setProvider(socialSignOnProvider.getProviderName());
|
||||
|
||||
Authentication authentication = authenticationProvider.authentication(loginCredential,true);
|
||||
Authentication authentication = authenticationProvider.authenticate(loginCredential,true);
|
||||
//socialsAssociate.setAccessToken(JsonUtils.object2Json(this.accessToken));
|
||||
socialsAssociate.setSocialUserInfo(accountJsonString);
|
||||
//socialsAssociate.setExAttribute(JsonUtils.object2Json(accessToken.getResponseObject()));
|
||||
|
||||
@ -30,7 +30,7 @@ public class InMemoryMomentaryService implements MomentaryService{
|
||||
|
||||
protected static Cache<String, Object> momentaryStore =
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(3, TimeUnit.MINUTES)
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.maximumSize(200000)
|
||||
.build();
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory;
|
||||
public class RedisMomentaryService implements MomentaryService {
|
||||
private static final Logger _logger = LoggerFactory.getLogger(RedisMomentaryService.class);
|
||||
|
||||
protected int validitySeconds = 60 * 3; //default 3 minutes.
|
||||
protected int validitySeconds = 60 * 5; //default 5 minutes.
|
||||
|
||||
RedisConnectionFactory connectionFactory;
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ public class CasRestV1Endpoint extends CasBaseAuthorizeEndpoint{
|
||||
|
||||
LoginCredential loginCredential =new LoginCredential(username,password,"CASREST");
|
||||
|
||||
authenticationProvider.authentication(loginCredential,false);
|
||||
authenticationProvider.authenticate(loginCredential,false);
|
||||
|
||||
TicketGrantingTicketImpl ticketGrantingTicket=new TicketGrantingTicketImpl("Random",AuthorizationUtils.getAuthentication(),null);
|
||||
|
||||
@ -187,7 +187,7 @@ public class CasRestV1Endpoint extends CasBaseAuthorizeEndpoint{
|
||||
|
||||
LoginCredential loginCredential =new LoginCredential(username,password,"CASREST");
|
||||
|
||||
authenticationProvider.authentication(loginCredential,false);
|
||||
authenticationProvider.authenticate(loginCredential,false);
|
||||
UserInfo userInfo = AuthorizationUtils.getUserInfo();
|
||||
TicketGrantingTicketImpl ticketGrantingTicket=new TicketGrantingTicketImpl("Random",AuthorizationUtils.getAuthentication(),null);
|
||||
|
||||
|
||||
@ -195,7 +195,7 @@ public class ConsumerEndpoint {
|
||||
LoginCredential loginCredential =new LoginCredential(
|
||||
username,"",ConstsLoginType.SAMLTRUST);
|
||||
|
||||
Authentication authentication = authenticationProvider.authentication(loginCredential,true);
|
||||
Authentication authentication = authenticationProvider.authenticate(loginCredential,true);
|
||||
if(authentication == null) {
|
||||
String congress = authJwtService.createCongress(authentication);
|
||||
}
|
||||
|
||||
@ -146,12 +146,20 @@ public class LoginEntryPoint {
|
||||
*/
|
||||
@RequestMapping(value={"/signin"}, produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
public ResponseEntity<?> signin( @RequestBody LoginCredential loginCredential) {
|
||||
|
||||
Authentication authentication = authenticationProvider.authenticate(loginCredential);
|
||||
if(authentication == null) {
|
||||
return new Message<AuthJwt>(Message.FAIL).buildResponse();
|
||||
Message<AuthJwt> authJwtMessage = new Message<AuthJwt>(Message.FAIL);
|
||||
if(authJwtService.validateJwtToken(loginCredential.getState())){
|
||||
String authType = loginCredential.getAuthType();
|
||||
_logger.debug("Login AuthN Type " + authType);
|
||||
if (StringUtils.isNotBlank(authType)){
|
||||
Authentication authentication = authenticationProvider.doAuthenticate(loginCredential);
|
||||
if(authentication != null) {
|
||||
authJwtMessage = new Message<AuthJwt>(authJwtService.genAuthJwt(authentication));
|
||||
}
|
||||
return new Message<AuthJwt>(authJwtService.genAuthJwt(authentication)).buildResponse();
|
||||
}else {
|
||||
_logger.error("Login AuthN type must eq normal , tfa or mobile . ");
|
||||
}
|
||||
}
|
||||
return authJwtMessage.buildResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
* Copyright [2022] [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.
|
||||
@ -17,6 +17,8 @@
|
||||
|
||||
package org.maxkey.web.contorller;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.maxkey.authn.AbstractAuthenticationProvider;
|
||||
import org.maxkey.authn.LoginCredential;
|
||||
import org.maxkey.authn.jwt.AuthJwt;
|
||||
@ -35,7 +37,6 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
|
||||
@ -48,14 +49,11 @@ public class LoginEntryPoint {
|
||||
private static Logger _logger = LoggerFactory.getLogger(LoginEntryPoint.class);
|
||||
|
||||
@Autowired
|
||||
@Qualifier("authJwtService")
|
||||
AuthJwtService authJwtService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("applicationConfig")
|
||||
protected ApplicationConfig applicationConfig;
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("authenticationProvider")
|
||||
AbstractAuthenticationProvider authenticationProvider ;
|
||||
@ -64,34 +62,28 @@ public class LoginEntryPoint {
|
||||
* init login
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value={"/login"})
|
||||
public ModelAndView login() {
|
||||
@RequestMapping(value={"/get"}, produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
public ResponseEntity<?> get() {
|
||||
_logger.debug("LoginController /login.");
|
||||
|
||||
boolean isAuthenticated= false;//WebContext.isAuthenticated();
|
||||
//for normal login
|
||||
if(isAuthenticated){
|
||||
return WebContext.redirect("/main");
|
||||
}
|
||||
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
HashMap<String , Object> model = new HashMap<String , Object>();
|
||||
model.put("isRemeberMe", applicationConfig.getLoginConfig().isRemeberMe());
|
||||
Institutions inst = (Institutions)WebContext.getAttribute(WebConstants.CURRENT_INST);
|
||||
modelAndView.addObject("isRemeberMe", applicationConfig.getLoginConfig().isRemeberMe());
|
||||
modelAndView.addObject("captchaSupport", inst.getCaptchaSupport());
|
||||
modelAndView.addObject("captchaType", inst.getCaptchaType());
|
||||
modelAndView.addObject("sessionid", WebContext.getSession().getId());
|
||||
Object loginErrorMessage=WebContext.getAttribute(WebConstants.LOGIN_ERROR_SESSION_MESSAGE);
|
||||
modelAndView.addObject("loginErrorMessage", loginErrorMessage==null?"":loginErrorMessage);
|
||||
WebContext.removeAttribute(WebConstants.LOGIN_ERROR_SESSION_MESSAGE);
|
||||
modelAndView.setViewName("login");
|
||||
return modelAndView;
|
||||
model.put("inst", inst);
|
||||
model.put("captcha", inst.getCaptchaSupport());
|
||||
model.put("captchaType", inst.getCaptchaType());
|
||||
model.put("state", authJwtService.genJwt());
|
||||
return new Message<HashMap<String , Object>>(model).buildResponse();
|
||||
}
|
||||
|
||||
@RequestMapping(value={"/signin"}, produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
public ResponseEntity<?> signin( @RequestBody LoginCredential loginCredential) {
|
||||
if(authJwtService.validateJwtToken(loginCredential.getState())){
|
||||
Authentication authentication = authenticationProvider.authenticate(loginCredential);
|
||||
AuthJwt authJwt = authJwtService.genAuthJwt(authentication);
|
||||
return new Message<AuthJwt>(authJwt).buildResponse();
|
||||
}
|
||||
return new Message<AuthJwt>(Message.FAIL).buildResponse();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user