diff --git a/maxkey-authentications/maxkey-authentication-captcha/build.gradle b/maxkey-authentications/maxkey-authentication-captcha/build.gradle index 1524a6250..7f6d1682a 100644 --- a/maxkey-authentications/maxkey-authentication-captcha/build.gradle +++ b/maxkey-authentications/maxkey-authentication-captcha/build.gradle @@ -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') } \ No newline at end of file diff --git a/maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptcha.java b/maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptcha.java new file mode 100644 index 000000000..1cef533b8 --- /dev/null +++ b/maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptcha.java @@ -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; + } + + + +} diff --git a/maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptchaBase64Endpoint.java b/maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptchaBase64Endpoint.java deleted file mode 100644 index cce0826f6..000000000 --- a/maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptchaBase64Endpoint.java +++ /dev/null @@ -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; - } - - -} diff --git a/maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptchaEndpoint.java b/maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptchaEndpoint.java index 1340838dc..b4d307008 100644 --- a/maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptchaEndpoint.java +++ b/maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptchaEndpoint.java @@ -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; @@ -41,13 +49,15 @@ import org.springframework.web.bind.annotation.RequestParam; @Controller 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. @@ -55,75 +65,55 @@ public class ImageCaptchaEndpoint { * @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 + ""); - } 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); + String kaptchaKey = ""; + if(StringUtils.isNotBlank(state) + && !state.equalsIgnoreCase("state") + && authJwtService.validateJwtToken(state)) { + JWTClaimsSet claim = authJwtService.resolve(state); + kaptchaKey = claim.getJWTID(); + }else { + kaptchaKey = WebContext.genId(); + } + _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( + 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) { diff --git a/maxkey-authentications/maxkey-authentication-captcha/src/main/resources/kaptcha.properties b/maxkey-authentications/maxkey-authentication-captcha/src/main/resources/kaptcha.properties index 72f5f7d11..5900c0c70 100644 --- a/maxkey-authentications/maxkey-authentication-captcha/src/main/resources/kaptcha.properties +++ b/maxkey-authentications/maxkey-authentication-captcha/src/main/resources/kaptcha.properties @@ -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.noise.color=white \ No newline at end of file +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 \ No newline at end of file diff --git a/maxkey-authentications/maxkey-authentication-captcha/src/main/resources/kaptcha_d.properties b/maxkey-authentications/maxkey-authentication-captcha/src/main/resources/kaptcha_d.properties new file mode 100644 index 000000000..72f5f7d11 --- /dev/null +++ b/maxkey-authentications/maxkey-authentication-captcha/src/main/resources/kaptcha_d.properties @@ -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 \ No newline at end of file diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java index 61ea5414c..f757c6f91 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java @@ -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 providers = + new HashMap(); + 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 grantedAdministratorsAuthoritys = new ArrayList(); 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) { - - HashMap sessionAttributeMap = new HashMap(); - for(String attributeName : WebContext.sessionAttributeNameList) { - sessionAttributeMap.put(attributeName, WebContext.getAttribute(attributeName)); - WebContext.removeAttribute(attributeName); - } - - //new Session - WebContext.getSession().invalidate(); - - for(String attributeName : WebContext.sessionAttributeNameList) { - WebContext.setAttribute(attributeName, sessionAttributeMap.get(attributeName)); - } + public Authentication authenticate(LoginCredential authentication){ + if(authentication.getAuthType().equalsIgnoreCase("trusted")) { + return null; + } + AbstractAuthenticationProvider provider = providers.get(authentication.getAuthType() + 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 Authentication authenticate(LoginCredential authentication,boolean trusted){ + AbstractAuthenticationProvider provider = providers.get(AuthType.TRUSTED + PROVIDER_SUFFIX); + return provider == null ? null : provider.doAuthenticate(authentication); } - - /** - * 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); + + public void addAuthenticationProvider(AbstractAuthenticationProvider provider) { + providers.put(provider.getProviderName(), provider); } - - 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 diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/LoginCredential.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/LoginCredential.java index bdc4b4f82..539ffc9ee 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/LoginCredential.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/LoginCredential.java @@ -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,15 +126,15 @@ 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() { + public String getCaptcha() { return captcha; } @@ -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="); diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/RealmAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/MfaAuthenticationProvider.java similarity index 65% rename from maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/RealmAuthenticationProvider.java rename to maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/MfaAuthenticationProvider.java index e47778811..5fa91835b 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/RealmAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/MfaAuthenticationProvider.java @@ -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,47 +48,40 @@ 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()); try { _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")) { @@ -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()); - } + + //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(); diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/MobileAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/MobileAuthenticationProvider.java new file mode 100644 index 000000000..68e47547e --- /dev/null +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/MobileAuthenticationProvider.java @@ -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); + } + } + } + +} diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/NormalAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/NormalAuthenticationProvider.java new file mode 100644 index 000000000..db9ad0f78 --- /dev/null +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/NormalAuthenticationProvider.java @@ -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 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; + } + +} diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/TrustedAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/TrustedAuthenticationProvider.java new file mode 100644 index 000000000..882b2e5e8 --- /dev/null +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/TrustedAuthenticationProvider.java @@ -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")); + } + } + +} diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/package-info.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/package-info.java new file mode 100644 index 000000000..e9a235b63 --- /dev/null +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/package-info.java @@ -0,0 +1 @@ +package org.maxkey.authn.provider; \ No newline at end of file diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/basic/BasicEntryPoint.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/basic/BasicEntryPoint.java index d5a196f90..06e14875c 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/basic/BasicEntryPoint.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/basic/BasicEntryPoint.java @@ -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 ."); } diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/httpheader/HttpHeaderEntryPoint.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/httpheader/HttpHeaderEntryPoint.java index 4a7190235..5d54c8773 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/httpheader/HttpHeaderEntryPoint.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/httpheader/HttpHeaderEntryPoint.java @@ -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 ."); } diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/jwt/HttpJwtEntryPoint.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/jwt/HttpJwtEntryPoint.java index 6f6c0d16b..78309adbd 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/jwt/HttpJwtEntryPoint.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/jwt/HttpJwtEntryPoint.java @@ -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); } diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/kerberos/HttpKerberosEntryPoint.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/kerberos/HttpKerberosEntryPoint.java index 2ce0e2385..15f2655e5 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/kerberos/HttpKerberosEntryPoint.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/kerberos/HttpKerberosEntryPoint.java @@ -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()); } diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/wsfederation/HttpWsFederationEntryPoint.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/wsfederation/HttpWsFederationEntryPoint.java index 886301edd..543a2e580 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/wsfederation/HttpWsFederationEntryPoint.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/wsfederation/HttpWsFederationEntryPoint.java @@ -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."); diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java index 020d31873..0d5515191 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java @@ -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") diff --git a/maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/SocialSignOnEndpoint.java b/maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/SocialSignOnEndpoint.java index 2b052f89d..33f39c8cd 100644 --- a/maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/SocialSignOnEndpoint.java +++ b/maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/SocialSignOnEndpoint.java @@ -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())); diff --git a/maxkey-core/src/main/java/org/maxkey/persistence/InMemoryMomentaryService.java b/maxkey-core/src/main/java/org/maxkey/persistence/InMemoryMomentaryService.java index bde781f4e..99f25cb46 100644 --- a/maxkey-core/src/main/java/org/maxkey/persistence/InMemoryMomentaryService.java +++ b/maxkey-core/src/main/java/org/maxkey/persistence/InMemoryMomentaryService.java @@ -30,7 +30,7 @@ public class InMemoryMomentaryService implements MomentaryService{ protected static Cache momentaryStore = Caffeine.newBuilder() - .expireAfterWrite(3, TimeUnit.MINUTES) + .expireAfterWrite(5, TimeUnit.MINUTES) .maximumSize(200000) .build(); diff --git a/maxkey-core/src/main/java/org/maxkey/persistence/RedisMomentaryService.java b/maxkey-core/src/main/java/org/maxkey/persistence/RedisMomentaryService.java index 3a877b704..48a5c7493 100644 --- a/maxkey-core/src/main/java/org/maxkey/persistence/RedisMomentaryService.java +++ b/maxkey-core/src/main/java/org/maxkey/persistence/RedisMomentaryService.java @@ -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; diff --git a/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasRestV1Endpoint.java b/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasRestV1Endpoint.java index 70be8b8cc..d91068291 100644 --- a/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasRestV1Endpoint.java +++ b/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasRestV1Endpoint.java @@ -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); diff --git a/maxkey-protocols/maxkey-protocol-saml-2.0/src/main/java/org/maxkey/authz/saml20/consumer/endpoint/ConsumerEndpoint.java b/maxkey-protocols/maxkey-protocol-saml-2.0/src/main/java/org/maxkey/authz/saml20/consumer/endpoint/ConsumerEndpoint.java index 4326e1636..010721920 100644 --- a/maxkey-protocols/maxkey-protocol-saml-2.0/src/main/java/org/maxkey/authz/saml20/consumer/endpoint/ConsumerEndpoint.java +++ b/maxkey-protocols/maxkey-protocol-saml-2.0/src/main/java/org/maxkey/authz/saml20/consumer/endpoint/ConsumerEndpoint.java @@ -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); } diff --git a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/endpoint/LoginEntryPoint.java b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/endpoint/LoginEntryPoint.java index 8b72a0fd8..f50d72d76 100644 --- a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/endpoint/LoginEntryPoint.java +++ b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/endpoint/LoginEntryPoint.java @@ -71,7 +71,7 @@ public class LoginEntryPoint { @Autowired @Qualifier("authenticationProvider") AbstractAuthenticationProvider authenticationProvider ; - + @Autowired @Qualifier("socialSignOnProviderService") SocialSignOnProviderService socialSignOnProviderService; @@ -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(Message.FAIL).buildResponse(); + Message authJwtMessage = new Message(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(authJwtService.genAuthJwt(authentication)); + } + }else { + _logger.error("Login AuthN type must eq normal , tfa or mobile . "); + } } - return new Message(authJwtService.genAuthJwt(authentication)).buildResponse(); + return authJwtMessage.buildResponse(); } /** diff --git a/maxkey-webs/maxkey-web-mgt/src/main/java/org/maxkey/web/contorller/LoginEntryPoint.java b/maxkey-webs/maxkey-web-mgt/src/main/java/org/maxkey/web/contorller/LoginEntryPoint.java index 42ac00b7e..de420f402 100644 --- a/maxkey-webs/maxkey-web-mgt/src/main/java/org/maxkey/web/contorller/LoginEntryPoint.java +++ b/maxkey-webs/maxkey-web-mgt/src/main/java/org/maxkey/web/contorller/LoginEntryPoint.java @@ -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 model = new HashMap(); + 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>(model).buildResponse(); } @RequestMapping(value={"/signin"}, produces = {MediaType.APPLICATION_JSON_VALUE}) public ResponseEntity signin( @RequestBody LoginCredential loginCredential) { - Authentication authentication = authenticationProvider.authenticate(loginCredential); - AuthJwt authJwt = authJwtService.genAuthJwt(authentication); - return new Message(authJwt).buildResponse(); + if(authJwtService.validateJwtToken(loginCredential.getState())){ + Authentication authentication = authenticationProvider.authenticate(loginCredential); + AuthJwt authJwt = authJwtService.genAuthJwt(authentication); + return new Message(authJwt).buildResponse(); + } + return new Message(Message.FAIL).buildResponse(); } }