MaxKey 3 anos atrás
pai
commit
7bba47a46c
26 arquivos alterados com 686 adições e 433 exclusões
  1. 3 0
      maxkey-authentications/maxkey-authentication-captcha/build.gradle
  2. 44 0
      maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptcha.java
  3. 0 142
      maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptchaBase64Endpoint.java
  4. 56 66
      maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptchaEndpoint.java
  5. 7 3
      maxkey-authentications/maxkey-authentication-captcha/src/main/resources/kaptcha.properties
  6. 9 0
      maxkey-authentications/maxkey-authentication-captcha/src/main/resources/kaptcha_d.properties
  7. 30 87
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java
  8. 14 12
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/LoginCredential.java
  9. 22 71
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/MfaAuthenticationProvider.java
  10. 142 0
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/MobileAuthenticationProvider.java
  11. 178 0
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/NormalAuthenticationProvider.java
  12. 84 0
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/TrustedAuthenticationProvider.java
  13. 1 0
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/package-info.java
  14. 1 1
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/basic/BasicEntryPoint.java
  15. 1 1
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/httpheader/HttpHeaderEntryPoint.java
  16. 1 1
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/jwt/HttpJwtEntryPoint.java
  17. 1 1
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/kerberos/HttpKerberosEntryPoint.java
  18. 1 1
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/support/wsfederation/HttpWsFederationEntryPoint.java
  19. 53 9
      maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java
  20. 1 1
      maxkey-authentications/maxkey-authentication-social/src/main/java/org/maxkey/authn/support/socialsignon/SocialSignOnEndpoint.java
  21. 1 1
      maxkey-core/src/main/java/org/maxkey/persistence/InMemoryMomentaryService.java
  22. 1 1
      maxkey-core/src/main/java/org/maxkey/persistence/RedisMomentaryService.java
  23. 2 2
      maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasRestV1Endpoint.java
  24. 1 1
      maxkey-protocols/maxkey-protocol-saml-2.0/src/main/java/org/maxkey/authz/saml20/consumer/endpoint/ConsumerEndpoint.java
  25. 14 6
      maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/endpoint/LoginEntryPoint.java
  26. 18 26
      maxkey-webs/maxkey-web-mgt/src/main/java/org/maxkey/web/contorller/LoginEntryPoint.java

+ 3 - 0
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')   
 }

+ 44 - 0
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;
+	}
+	
+	
+	
+}

+ 0 - 142
maxkey-authentications/maxkey-authentication-captcha/src/main/java/org/maxkey/web/contorller/ImageCaptchaBase64Endpoint.java

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

+ 56 - 66
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 com.nimbusds.jwt.JWTClaimsSet;
+
 import java.awt.image.BufferedImage;
-import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+import java.util.Base64;
+
 import javax.imageio.ImageIO;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 
+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<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) {

+ 7 - 3
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
+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

+ 9 - 0
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

+ 30 - 87
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<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) {
-        
-        HashMap<String,Object> sessionAttributeMap = new HashMap<String,Object>();
-        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);
-        }
-    }
-
-    /**
-     * 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 Authentication authenticate(LoginCredential authentication,boolean trusted){
+    	AbstractAuthenticationProvider provider = providers.get(AuthType.TRUSTED + PROVIDER_SUFFIX);
+    	return provider == null ? null : provider.doAuthenticate(authentication);
     }
-
-    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);
+    
+    public void addAuthenticationProvider(AbstractAuthenticationProvider provider) {
+    	providers.put(provider.getProviderName(), provider);
     }
-
     /**
      * 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

+ 14 - 12
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=");

+ 22 - 71
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/RealmAuthenticationProvider.java → 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();

+ 142 - 0
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);
+            }
+        }
+    }
+  
+}

+ 178 - 0
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<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;
+    }
+  
+}

+ 84 - 0
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"));
+        }
+    }
+  
+}

+ 1 - 0
maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/provider/package-info.java

@@ -0,0 +1 @@
+package org.maxkey.authn.provider;

+ 1 - 1
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 .");
 		 }
 		

+ 1 - 1
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 .");
 		 }
 		

+ 1 - 1
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);
 		 }
 		

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

+ 1 - 1
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.");

+ 53 - 9
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")

+ 1 - 1
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()));

+ 1 - 1
maxkey-core/src/main/java/org/maxkey/persistence/InMemoryMomentaryService.java

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

+ 1 - 1
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;
 	

+ 2 - 2
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);
             

+ 1 - 1
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);
 		}

+ 14 - 6
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<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));
+		 		}
+ 	        }else {
+ 	        	_logger.error("Login AuthN type must eq normal , tfa or mobile . ");
+ 	        }
  		}
- 		return new Message<AuthJwt>(authJwtService.genAuthJwt(authentication)).buildResponse();
+ 		return authJwtMessage.buildResponse();
  	}
  	
  	/**

+ 18 - 26
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<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) {
- 		Authentication  authentication  = authenticationProvider.authenticate(loginCredential);
- 		AuthJwt authJwt = authJwtService.genAuthJwt(authentication);
- 		return new Message<AuthJwt>(authJwt).buildResponse();
+ 		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();
  	}
  	
 }