diff --git a/maxkey-core/src/main/java/org/maxkey/constants/ConstantsProtocols.java b/maxkey-core/src/main/java/org/maxkey/constants/ConstantsProtocols.java index 39bf7f18..85d0f299 100644 --- a/maxkey-core/src/main/java/org/maxkey/constants/ConstantsProtocols.java +++ b/maxkey-core/src/main/java/org/maxkey/constants/ConstantsProtocols.java @@ -42,5 +42,7 @@ public final class ConstantsProtocols { public static final String OPEN_ID_CONNECT = "OpenID_Connect"; public static final String CAS = "CAS"; + + public static final String JWT = "JWT"; } diff --git a/maxkey-core/src/main/java/org/maxkey/domain/apps/AppsJwtDetails.java b/maxkey-core/src/main/java/org/maxkey/domain/apps/AppsJwtDetails.java new file mode 100644 index 00000000..4bc99e76 --- /dev/null +++ b/maxkey-core/src/main/java/org/maxkey/domain/apps/AppsJwtDetails.java @@ -0,0 +1,159 @@ +/* + * 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.domain.apps; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +/** + * @author Crystal.Sea + * + */ +@Table(name = "MXK_APPS_JWT_DETAILS") +public class AppsJwtDetails extends Apps { + + /** + * + */ + private static final long serialVersionUID = -1717427271305620545L; + + @Id + @Column + @GeneratedValue(strategy=GenerationType.AUTO,generator="uuid") + protected String id; + /** + * + */ + @Column + private String redirectUri; + // + @Column + private String tokenType; + @Column + private String cookieName; + @Column + private String algorithm; + @Column + private String algorithmKey; + @Column + private String expires; + + + public AppsJwtDetails() { + super(); + } + + + public String getId() { + return id; + } + + + public void setId(String id) { + this.id = id; + } + + + public String getRedirectUri() { + return redirectUri; + } + + + public void setRedirectUri(String redirectUri) { + this.redirectUri = redirectUri; + } + + + public String getTokenType() { + return tokenType; + } + + + public void setTokenType(String tokenType) { + this.tokenType = tokenType; + } + + + public String getCookieName() { + return cookieName; + } + + + public void setCookieName(String cookieName) { + this.cookieName = cookieName; + } + + + public String getAlgorithm() { + return algorithm; + } + + + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + + public String getAlgorithmKey() { + return algorithmKey; + } + + + public void setAlgorithmKey(String algorithmKey) { + this.algorithmKey = algorithmKey; + } + + + public String getExpires() { + return expires; + } + + + public void setExpires(String expires) { + this.expires = expires; + } + + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("AppsTokenBasedDetails [id="); + builder.append(id); + builder.append(", redirectUri="); + builder.append(redirectUri); + builder.append(", tokenType="); + builder.append(tokenType); + builder.append(", cookieName="); + builder.append(cookieName); + builder.append(", algorithm="); + builder.append(algorithm); + builder.append(", algorithmKey="); + builder.append(algorithmKey); + builder.append(", expires="); + builder.append(expires); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/maxkey-persistence/src/main/java/org/maxkey/persistence/mapper/AppsJwtDetailsMapper.java b/maxkey-persistence/src/main/java/org/maxkey/persistence/mapper/AppsJwtDetailsMapper.java new file mode 100644 index 00000000..586eae8f --- /dev/null +++ b/maxkey-persistence/src/main/java/org/maxkey/persistence/mapper/AppsJwtDetailsMapper.java @@ -0,0 +1,33 @@ +/* + * 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.persistence.mapper; + +import org.apache.mybatis.jpa.persistence.IJpaBaseMapper; +import org.maxkey.domain.apps.AppsJwtDetails; + +/** + * @author Crystal.sea + * + */ +public interface AppsJwtDetailsMapper extends IJpaBaseMapper { + + public AppsJwtDetails getAppDetails(String id); +} diff --git a/maxkey-persistence/src/main/java/org/maxkey/persistence/service/AppsJwtDetailsService.java b/maxkey-persistence/src/main/java/org/maxkey/persistence/service/AppsJwtDetailsService.java new file mode 100644 index 00000000..54d21974 --- /dev/null +++ b/maxkey-persistence/src/main/java/org/maxkey/persistence/service/AppsJwtDetailsService.java @@ -0,0 +1,44 @@ +/* + * 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.persistence.service; + +import org.apache.mybatis.jpa.persistence.JpaBaseService; +import org.maxkey.domain.apps.AppsJwtDetails; +import org.maxkey.persistence.mapper.AppsJwtDetailsMapper; +import org.springframework.stereotype.Service; + +@Service +public class AppsJwtDetailsService extends JpaBaseService{ + + public AppsJwtDetailsService() { + super(AppsJwtDetailsMapper.class); + } + + /* (non-Javadoc) + * @see com.connsec.db.service.BaseService#getMapper() + */ + @Override + public AppsJwtDetailsMapper getMapper() { + // TODO Auto-generated method stub + return (AppsJwtDetailsMapper)super.getMapper(); + } + + public AppsJwtDetails getAppDetails(String id) { + return getMapper().getAppDetails(id); + } +} diff --git a/maxkey-persistence/src/main/resources/org/maxkey/persistence/mapper/xml/mysql/AppsJwtDetailsMapper.xml b/maxkey-persistence/src/main/resources/org/maxkey/persistence/mapper/xml/mysql/AppsJwtDetailsMapper.xml new file mode 100644 index 00000000..2d14d1fb --- /dev/null +++ b/maxkey-persistence/src/main/resources/org/maxkey/persistence/mapper/xml/mysql/AppsJwtDetailsMapper.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/endpoint/AuthorizeEndpoint.java b/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/endpoint/AuthorizeEndpoint.java index 7e30129a..43d60a2f 100644 --- a/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/endpoint/AuthorizeEndpoint.java +++ b/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/endpoint/AuthorizeEndpoint.java @@ -68,7 +68,9 @@ public class AuthorizeEndpoint extends AuthorizeBaseEndpoint{ modelAndView=WebContext.forward("/authz/tokenbased/"+id); }else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.CAS)){ modelAndView=WebContext.forward("/authz/cas/"+id); - }else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.DESKTOP)){ + }else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.JWT)){ + modelAndView=WebContext.forward("/authz/jwt/"+id); + }else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.DESKTOP)){ modelAndView=WebContext.forward("/authz/desktop/"+id); }else if (application.getProtocol().equalsIgnoreCase(ConstantsProtocols.BASIC)){ modelAndView=WebContext.redirect(application.getLoginUrl()); @@ -78,14 +80,5 @@ public class AuthorizeEndpoint extends AuthorizeBaseEndpoint{ return modelAndView; } - - @RequestMapping("/authz/oauth10a/{id}") - public ModelAndView authorizeOAuth10a( - @PathVariable("id") String id){ - - String redirec_uri=getApp(id).getLoginUrl(); - return WebContext.redirect(redirec_uri); - - } } diff --git a/maxkey-protocols/maxkey-protocol-jwt/build.gradle b/maxkey-protocols/maxkey-protocol-jwt/build.gradle new file mode 100644 index 00000000..6410efba --- /dev/null +++ b/maxkey-protocols/maxkey-protocol-jwt/build.gradle @@ -0,0 +1,13 @@ + +description = "maxkey-protocol-jwt" + + +dependencies { + //local jars + compile fileTree(dir: '../maxkey-lib/*/', include: '*.jar') + + compile project(":maxkey-core") + compile project(":maxkey-persistence") + compile project(":maxkey-protocols:maxkey-protocol-authorize") + +} \ No newline at end of file diff --git a/maxkey-protocols/maxkey-protocol-jwt/src/main/java/META-INF/MANIFEST.MF b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 00000000..254272e1 --- /dev/null +++ b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/maxkey-protocols/maxkey-protocol-tokenbased/src/main/java/org/maxkey/authz/token/endpoint/adapter/TokenBasedJWTAdapter.java b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtAdapter.java similarity index 89% rename from maxkey-protocols/maxkey-protocol-tokenbased/src/main/java/org/maxkey/authz/token/endpoint/adapter/TokenBasedJWTAdapter.java rename to maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtAdapter.java index 9f2107b7..5f252cee 100644 --- a/maxkey-protocols/maxkey-protocol-tokenbased/src/main/java/org/maxkey/authz/token/endpoint/adapter/TokenBasedJWTAdapter.java +++ b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtAdapter.java @@ -15,7 +15,7 @@ */ -package org.maxkey.authz.token.endpoint.adapter; +package org.maxkey.authz.jwt.endpoint.adapter; import java.util.Arrays; import java.util.Date; @@ -28,7 +28,7 @@ import org.maxkey.configuration.oidc.OIDCProviderMetadata; import org.maxkey.crypto.jwt.signer.service.JwtSigningAndValidationService; import org.maxkey.domain.UserInfo; import org.maxkey.domain.apps.Apps; -import org.maxkey.domain.apps.AppsTokenBasedDetails; +import org.maxkey.domain.apps.AppsJwtDetails; import org.maxkey.web.WebConstants; import org.maxkey.web.WebContext; import org.slf4j.Logger; @@ -42,11 +42,11 @@ import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.PlainJWT; import com.nimbusds.jwt.SignedJWT; -public class TokenBasedJWTAdapter extends AbstractAuthorizeAdapter { - final static Logger _logger = LoggerFactory.getLogger(TokenBasedJWTAdapter.class); +public class JwtAdapter extends AbstractAuthorizeAdapter { + final static Logger _logger = LoggerFactory.getLogger(JwtAdapter.class); @Override public String generateInfo(SigninPrincipal authentication,UserInfo userInfo,Object app) { - AppsTokenBasedDetails details=(AppsTokenBasedDetails)app; + AppsJwtDetails details=(AppsJwtDetails)app; JwtSigningAndValidationService jwtSignerService= (JwtSigningAndValidationService)WebContext.getBean("jwtSignerValidationService"); @@ -111,8 +111,8 @@ public class TokenBasedJWTAdapter extends AbstractAuthorizeAdapter { @Override public ModelAndView authorize(UserInfo userInfo, Object app, String data,ModelAndView modelAndView) { - modelAndView.setViewName("authorize/tokenbased_jwt_sso_submint"); - AppsTokenBasedDetails details=(AppsTokenBasedDetails)app; + modelAndView.setViewName("authorize/jwt_sso_submint"); + AppsJwtDetails details=(AppsJwtDetails)app; modelAndView.addObject("action", details.getRedirectUri()); _logger.debug("jwt Token data : "+data); diff --git a/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtDefaultAdapter.java b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtDefaultAdapter.java new file mode 100644 index 00000000..53282b56 --- /dev/null +++ b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtDefaultAdapter.java @@ -0,0 +1,114 @@ +/* + * 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.authz.jwt.endpoint.adapter; + +import java.util.Arrays; +import java.util.Date; +import java.util.UUID; + +import org.joda.time.DateTime; +import org.maxkey.authn.SigninPrincipal; +import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter; +import org.maxkey.configuration.oidc.OIDCProviderMetadata; +import org.maxkey.crypto.jwt.signer.service.JwtSigningAndValidationService; +import org.maxkey.domain.UserInfo; +import org.maxkey.domain.apps.AppsJwtDetails; +import org.maxkey.web.WebConstants; +import org.maxkey.web.WebContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.servlet.ModelAndView; + +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.PlainJWT; +import com.nimbusds.jwt.SignedJWT; + +public class JwtDefaultAdapter extends AbstractAuthorizeAdapter { + final static Logger _logger = LoggerFactory.getLogger(JwtDefaultAdapter.class); + @Override + public String generateInfo(SigninPrincipal authentication,UserInfo userInfo,Object app) { + AppsJwtDetails details=(AppsJwtDetails)app; + + + JwtSigningAndValidationService jwtSignerService= (JwtSigningAndValidationService)WebContext.getBean("jwtSignerValidationService"); + OIDCProviderMetadata providerMetadata= (OIDCProviderMetadata)WebContext.getBean("oidcProviderMetadata"); + + DateTime currentDateTime=DateTime.now(); + + Date expirationTime=currentDateTime.plusMinutes(Integer.parseInt(details.getExpires())).toDate(); + _logger.debug("expiration Time : "+expirationTime); + + JWTClaimsSet jwtClaims =new JWTClaimsSet.Builder() + .issuer(providerMetadata.getIssuer()) + .subject(userInfo.getUsername()) + .audience(Arrays.asList(details.getId())) + .jwtID(UUID.randomUUID().toString()) + .issueTime(currentDateTime.toDate()) + .expirationTime(expirationTime) + .claim("email", userInfo.getWorkEmail()) + .claim("name", userInfo.getUsername()) + .claim("user_id", userInfo.getId()) + .claim("external_id", userInfo.getId()) + .claim("locale", userInfo.getLocale()) + .claim(WebConstants.ONLINE_TICKET_NAME, authentication.getOnlineTicket().getTicketId()) + .claim("kid", jwtSignerService.getDefaultSignerKeyId()) + .build(); + + _logger.debug("jwt Claims : "+jwtClaims); + + JWT jwtToken = new PlainJWT(jwtClaims); + + JWSAlgorithm signingAlg = jwtSignerService.getDefaultSigningAlgorithm(); + + //get PublicKey + /*Map jwkMap=jwtSignerService.getAllPublicKeys(); + + JWK jwk=jwkMap.get("connsec_rsa1"); + + _logger.debug("isPrivate "+jwk.isPrivate());*/ + + _logger.debug(" signingAlg "+signingAlg); + + jwtToken = new SignedJWT(new JWSHeader(signingAlg), jwtClaims); + // sign it with the server's key + jwtSignerService.signJwt((SignedJWT) jwtToken); + + String tokenString=jwtToken.serialize(); + _logger.debug("jwt Token : "+tokenString); + + return tokenString; + } + + @Override + public String encrypt(String data, String algorithmKey, String algorithm) { + return super.encrypt(data, algorithmKey, algorithm); + } + + @Override + public ModelAndView authorize(UserInfo userInfo, Object app, String data,ModelAndView modelAndView) { + modelAndView.setViewName("authorize/jwt_sso_submint"); + AppsJwtDetails details=(AppsJwtDetails)app; + modelAndView.addObject("action", details.getRedirectUri()); + + modelAndView.addObject("token",data ); + return modelAndView; + } +} diff --git a/maxkey-protocols/maxkey-protocol-tokenbased/src/main/java/org/maxkey/authz/token/endpoint/adapter/TokenBasedJWTHS256Adapter.java b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtHS256Adapter.java similarity index 89% rename from maxkey-protocols/maxkey-protocol-tokenbased/src/main/java/org/maxkey/authz/token/endpoint/adapter/TokenBasedJWTHS256Adapter.java rename to maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtHS256Adapter.java index 7de272d2..e699d03d 100644 --- a/maxkey-protocols/maxkey-protocol-tokenbased/src/main/java/org/maxkey/authz/token/endpoint/adapter/TokenBasedJWTHS256Adapter.java +++ b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/jwt/endpoint/adapter/JwtHS256Adapter.java @@ -15,7 +15,7 @@ */ -package org.maxkey.authz.token.endpoint.adapter; +package org.maxkey.authz.jwt.endpoint.adapter; import java.util.Arrays; import java.util.Date; @@ -30,7 +30,7 @@ import org.maxkey.crypto.jwt.signer.service.JwtSigningAndValidationService; import org.maxkey.crypto.jwt.signer.service.impl.SymmetricSigningAndValidationServiceBuilder; import org.maxkey.domain.UserInfo; import org.maxkey.domain.apps.Apps; -import org.maxkey.domain.apps.AppsTokenBasedDetails; +import org.maxkey.domain.apps.AppsJwtDetails; import org.maxkey.web.WebConstants; import org.maxkey.web.WebContext; import org.slf4j.Logger; @@ -44,13 +44,13 @@ import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.PlainJWT; import com.nimbusds.jwt.SignedJWT; -public class TokenBasedJWTHS256Adapter extends AbstractAuthorizeAdapter { - final static Logger _logger = LoggerFactory.getLogger(TokenBasedJWTHS256Adapter.class); +public class JwtHS256Adapter extends AbstractAuthorizeAdapter { + final static Logger _logger = LoggerFactory.getLogger(JwtHS256Adapter.class); private SymmetricSigningAndValidationServiceBuilder symmetricJwtSignerServiceBuilder=new SymmetricSigningAndValidationServiceBuilder(); @Override public String generateInfo(SigninPrincipal authentication,UserInfo userInfo,Object app) { - AppsTokenBasedDetails details=(AppsTokenBasedDetails)app; + AppsJwtDetails details=(AppsJwtDetails)app; OIDCProviderMetadata providerMetadata= (OIDCProviderMetadata)WebContext.getBean("oidcProviderMetadata"); @@ -108,8 +108,8 @@ public class TokenBasedJWTHS256Adapter extends AbstractAuthorizeAdapter { @Override public ModelAndView authorize(UserInfo userInfo, Object app, String data,ModelAndView modelAndView) { - modelAndView.setViewName("authorize/tokenbased_jwt_sso_submint"); - AppsTokenBasedDetails details=(AppsTokenBasedDetails)app; + modelAndView.setViewName("authorize/jwt_sso_submint"); + AppsJwtDetails details=(AppsJwtDetails)app; modelAndView.addObject("action", details.getRedirectUri()); _logger.debug("jwt Token data : "+data); diff --git a/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/token/endpoint/JwtAuthorizeEndpoint.java b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/token/endpoint/JwtAuthorizeEndpoint.java new file mode 100644 index 00000000..720cc7e5 --- /dev/null +++ b/maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/token/endpoint/JwtAuthorizeEndpoint.java @@ -0,0 +1,140 @@ +/* + * 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.authz.token.endpoint; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.maxkey.authn.SigninPrincipal; +import org.maxkey.authz.endpoint.AuthorizeBaseEndpoint; +import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter; +import org.maxkey.authz.jwt.endpoint.adapter.JwtDefaultAdapter; +import org.maxkey.configuration.ApplicationConfig; +import org.maxkey.constants.Boolean; +import org.maxkey.domain.apps.Apps; +import org.maxkey.domain.apps.AppsJwtDetails; +import org.maxkey.persistence.service.AppsJwtDetailsService; +import org.maxkey.util.Instance; +import org.maxkey.web.WebContext; +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.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +/** + * @author Crystal.Sea + * + */ +@Controller +public class JwtAuthorizeEndpoint extends AuthorizeBaseEndpoint{ + + final static Logger _logger = LoggerFactory.getLogger(JwtAuthorizeEndpoint.class); + + @Autowired + AppsJwtDetailsService jwtDetailsService; + + JwtDefaultAdapter jwtDefaultAdapter=new JwtDefaultAdapter(); + + @Autowired + ApplicationConfig applicationConfig; + + @RequestMapping("/authz/jwt/{id}") + public ModelAndView authorize( + HttpServletRequest request, + HttpServletResponse response, + @PathVariable("id") String id){ + ModelAndView modelAndView=new ModelAndView(); + + + AppsJwtDetails jwtDetails=null; + jwtDetails=jwtDetailsService.getAppDetails(id); + _logger.debug(""+jwtDetails); + + Apps application= getApp(id); + jwtDetails.setAdapter(application.getAdapter()); + jwtDetails.setIsAdapter(application.getIsAdapter()); + + AbstractAuthorizeAdapter adapter; + if(Boolean.isTrue(jwtDetails.getIsAdapter())){ + adapter =(AbstractAuthorizeAdapter)Instance.newInstance(jwtDetails.getAdapter()); + }else{ + adapter =(AbstractAuthorizeAdapter)jwtDefaultAdapter; + } + + String tokenData=adapter.generateInfo( + (SigninPrincipal)WebContext.getAuthentication().getPrincipal(), + WebContext.getUserInfo(), + jwtDetails); + + String encryptTokenData=adapter.encrypt( + tokenData, + jwtDetails.getAlgorithmKey(), + jwtDetails.getAlgorithm()); + + String signTokenData=adapter.sign( + encryptTokenData, + jwtDetails); + + if(jwtDetails.getTokenType().equalsIgnoreCase("POST")) { + modelAndView=adapter.authorize( + WebContext.getUserInfo(), + jwtDetails, + signTokenData, + modelAndView); + + return modelAndView; + }else { + + String cookieValue=""; + cookieValue=signTokenData; + + _logger.debug("Cookie Name : "+jwtDetails.getCookieName()); + + Cookie cookie= new Cookie(jwtDetails.getCookieName(),cookieValue); + + Integer maxAge=Integer.parseInt(jwtDetails.getExpires())*60; + _logger.debug("Cookie Max Age :"+maxAge+" seconds."); + cookie.setMaxAge(maxAge); + + cookie.setPath("/"); + // + //cookie.setDomain("."+applicationConfig.getBaseDomainName()); + //tomcat 8.5 + cookie.setDomain(applicationConfig.getBaseDomainName()); + + _logger.debug("Sub Domain Name : "+"."+applicationConfig.getBaseDomainName()); + response.addCookie(cookie); + + if(jwtDetails.getRedirectUri().indexOf(applicationConfig.getBaseDomainName())>-1){ + return WebContext.redirect(jwtDetails.getRedirectUri()); + }else{ + _logger.error(jwtDetails.getRedirectUri()+" not in domain "+applicationConfig.getBaseDomainName()); + return null; + } + } + + } + +} diff --git a/maxkey-web-manage/src/main/java/org/maxkey/web/apps/contorller/JwtDetailsController.java b/maxkey-web-manage/src/main/java/org/maxkey/web/apps/contorller/JwtDetailsController.java new file mode 100644 index 00000000..b1d19048 --- /dev/null +++ b/maxkey-web-manage/src/main/java/org/maxkey/web/apps/contorller/JwtDetailsController.java @@ -0,0 +1,125 @@ +/* + * 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.apps.contorller; + +import org.maxkey.constants.ConstantsOperateMessage; +import org.maxkey.constants.ConstantsProtocols; +import org.maxkey.crypto.ReciprocalUtils; +import org.maxkey.domain.apps.AppsJwtDetails; +import org.maxkey.persistence.service.AppsJwtDetailsService; +import org.maxkey.web.WebContext; +import org.maxkey.web.message.Message; +import org.maxkey.web.message.MessageType; +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.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; + + +@Controller +@RequestMapping(value={"/apps/jwt"}) +public class JwtDetailsController extends BaseAppContorller { + final static Logger _logger = LoggerFactory.getLogger(JwtDetailsController.class); + + @Autowired + AppsJwtDetailsService jwtDetailsService; + + + @RequestMapping(value = { "/forwardAdd" }) + public ModelAndView forwardAdd() { + ModelAndView modelAndView=new ModelAndView("apps/jwt/appAdd"); + AppsJwtDetails jwtDetails =new AppsJwtDetails(); + jwtDetails.setId(jwtDetails.generateId()); + jwtDetails.setProtocol(ConstantsProtocols.JWT); + jwtDetails.setSecret(ReciprocalUtils.generateKey(ReciprocalUtils.Algorithm.AES)); + jwtDetails.setAlgorithmKey(jwtDetails.getSecret()); + jwtDetails.setUserPropertys("userPropertys"); + modelAndView.addObject("model",jwtDetails); + return modelAndView; + } + + + @RequestMapping(value={"/add"}) + public ModelAndView insert(@ModelAttribute("jwtDetails") AppsJwtDetails jwtDetails) { + _logger.debug("-Add :" + jwtDetails); + + transform(jwtDetails); + + jwtDetails.setAlgorithmKey(jwtDetails.getSecret()); + + if (jwtDetailsService.insert(jwtDetails)&&appsService.insertApp(jwtDetails)) { + new Message(WebContext.getI18nValue(ConstantsOperateMessage.INSERT_SUCCESS),MessageType.success); + + } else { + new Message(WebContext.getI18nValue(ConstantsOperateMessage.INSERT_SUCCESS),MessageType.error); + } + return WebContext.forward("forwardUpdate/"+jwtDetails.getId()); + } + + @RequestMapping(value = { "/forwardUpdate/{id}" }) + public ModelAndView forwardUpdate(@PathVariable("id") String id) { + ModelAndView modelAndView=new ModelAndView("apps/jwt/appUpdate"); + AppsJwtDetails jwtDetails=jwtDetailsService.getAppDetails(id); + decoderSecret(jwtDetails); + String algorithmKey=passwordReciprocal.decoder(jwtDetails.getAlgorithmKey()); + jwtDetails.setAlgorithmKey(algorithmKey); + WebContext.setAttribute(jwtDetails.getId(), jwtDetails.getIcon()); + + modelAndView.addObject("model",jwtDetails); + return modelAndView; + } + /** + * modify + * @param application + * @return + */ + @RequestMapping(value={"/update"}) + public ModelAndView update(@ModelAttribute("jwtDetails") AppsJwtDetails jwtDetails) { + // + _logger.debug("-update application :" + jwtDetails); + transform(jwtDetails); + jwtDetails.setAlgorithmKey(jwtDetails.getSecret()); + if (jwtDetailsService.update(jwtDetails)&&appsService.updateApp(jwtDetails)) { + new Message(WebContext.getI18nValue(ConstantsOperateMessage.UPDATE_SUCCESS),MessageType.success); + + } else { + new Message(WebContext.getI18nValue(ConstantsOperateMessage.UPDATE_ERROR),MessageType.error); + } + return WebContext.forward("forwardUpdate/"+jwtDetails.getId()); + } + + + @ResponseBody + @RequestMapping(value={"/delete/{id}"}) + public Message delete(@PathVariable("id") String id) { + _logger.debug("-delete application :" + id); + if (jwtDetailsService.remove(id)&&appsService.remove(id)) { + return new Message(WebContext.getI18nValue(ConstantsOperateMessage.DELETE_SUCCESS),MessageType.success); + + } else { + return new Message(WebContext.getI18nValue(ConstantsOperateMessage.DELETE_SUCCESS),MessageType.error); + } + } + + +} diff --git a/maxkey-web-manage/src/main/resources/application.properties b/maxkey-web-manage/src/main/resources/application.properties index a29a9c02..e47da353 100644 --- a/maxkey-web-manage/src/main/resources/application.properties +++ b/maxkey-web-manage/src/main/resources/application.properties @@ -2,7 +2,7 @@ #application application.title=MaxKey application.name=MaxKey-Mgt -application.formatted-version=v2.3.0 GA +application.formatted-version=v2.4.0 GA #server config #server port server.port=9521 diff --git a/maxkey-web-manage/src/main/resources/messages/message.properties b/maxkey-web-manage/src/main/resources/messages/message.properties index ce6af876..29f8cff3 100644 --- a/maxkey-web-manage/src/main/resources/messages/message.properties +++ b/maxkey-web-manage/src/main/resources/messages/message.properties @@ -269,6 +269,7 @@ apps.protocol.oauth2.0=OAuth2.0 apps.protocol.saml2.0=SAML2.0 apps.protocol.ltpa=\u8f7b\u91cf\u7ea7\u8ba4\u8bc1(LTPA) apps.protocol.cas=CAS\u8ba4\u8bc1 +apps.protocol.jwt=JWT\u4ee4\u724c apps.protocol.extendapi=API\u6269\u5c55\u8ba4\u8bc1 apps.protocol.basic=\u57fa\u672c\u767b\u5f55 apps.vendor=\u4f9b\u5e94\u5546 @@ -339,6 +340,15 @@ apps.tokenbased.algorithm=\u52a0\u5bc6\u7b97\u6cd5 apps.tokenbased.algorithmKey=\u79d8\u94a5 apps.tokenbased.token.content=\u4ee4\u724c\u5185\u5bb9 apps.tokenbased.expires=\u8fc7\u671f\u65f6\u95f4 +#JWT +apps.jwt.info=JWT\u8ba4\u8bc1 +apps.jwt.redirectUri=\u8ba4\u8bc1\u5730\u5740 +apps.jwt.tokenType=\u4ee4\u724c\u7c7b\u578b +apps.jwt.cookieName=Cookie\u540d\u79f0 +apps.jwt.algorithm=\u52a0\u5bc6\u7b97\u6cd5 +apps.jwt.algorithmKey=\u79d8\u94a5 +apps.jwt.content=\u4ee4\u724c\u5185\u5bb9 +apps.jwt.expires=\u8fc7\u671f\u65f6\u95f4 #SAML apps.saml.metadata.company=\u516c\u53f8 apps.saml.spAcsUrl=SP ACS Url diff --git a/maxkey-web-manage/src/main/resources/messages/message_en.properties b/maxkey-web-manage/src/main/resources/messages/message_en.properties index b191bdc1..4796958e 100644 --- a/maxkey-web-manage/src/main/resources/messages/message_en.properties +++ b/maxkey-web-manage/src/main/resources/messages/message_en.properties @@ -269,6 +269,7 @@ apps.protocol.oauth2.0=OAuth2.0 apps.protocol.saml2.0=SAML2.0 apps.protocol.ltpa=Lightweight Third-Party(LTPA) apps.protocol.cas=CAS +apps.protocol.jwt=JwtToken apps.protocol.extendapi=API Extend apps.protocol.basic=Basic apps.vendor=vendor @@ -338,6 +339,15 @@ apps.tokenbased.algorithm=algorithm apps.tokenbased.algorithmKey=algorithmKey apps.tokenbased.token.content=content apps.tokenbased.expires=expires +#jwt +apps.jwt.info=JWT Info +apps.jwt.redirectUri=redirectUri +apps.jwt.tokenType=tokenType +apps.jwt.cookieName=Cookie Name +apps.jwt.algorithm=algorithm +apps.jwt.algorithmKey=algorithmKey +apps.jwt.content=content +apps.jwt.expires=expires #SAML apps.saml.metadata.company=company apps.saml.spAcsUrl=SP ACS Url diff --git a/maxkey-web-manage/src/main/resources/messages/message_zh_CN.properties b/maxkey-web-manage/src/main/resources/messages/message_zh_CN.properties index ce6af876..7987ea7f 100644 --- a/maxkey-web-manage/src/main/resources/messages/message_zh_CN.properties +++ b/maxkey-web-manage/src/main/resources/messages/message_zh_CN.properties @@ -269,6 +269,7 @@ apps.protocol.oauth2.0=OAuth2.0 apps.protocol.saml2.0=SAML2.0 apps.protocol.ltpa=\u8f7b\u91cf\u7ea7\u8ba4\u8bc1(LTPA) apps.protocol.cas=CAS\u8ba4\u8bc1 +apps.protocol.jwt=JWT\u4ee4\u724c apps.protocol.extendapi=API\u6269\u5c55\u8ba4\u8bc1 apps.protocol.basic=\u57fa\u672c\u767b\u5f55 apps.vendor=\u4f9b\u5e94\u5546 @@ -339,6 +340,16 @@ apps.tokenbased.algorithm=\u52a0\u5bc6\u7b97\u6cd5 apps.tokenbased.algorithmKey=\u79d8\u94a5 apps.tokenbased.token.content=\u4ee4\u724c\u5185\u5bb9 apps.tokenbased.expires=\u8fc7\u671f\u65f6\u95f4 +#JWT +#tokenbased +apps.jwt.info=JWT\u8ba4\u8bc1 +apps.jwt.redirectUri=\u8ba4\u8bc1\u5730\u5740 +apps.jwt.tokenType=\u4ee4\u724c\u7c7b\u578b +apps.jwt.cookieName=Cookie\u540d\u79f0 +apps.jwt.algorithm=\u52a0\u5bc6\u7b97\u6cd5 +apps.jwt.algorithmKey=\u79d8\u94a5 +apps.jwt.content=\u4ee4\u724c\u5185\u5bb9 +apps.jwt.expires=\u8fc7\u671f\u65f6\u95f4 #SAML apps.saml.metadata.company=\u516c\u53f8 apps.saml.spAcsUrl=SP ACS Url diff --git a/maxkey-web-manage/src/main/resources/templates/views/apps/appsList.ftl b/maxkey-web-manage/src/main/resources/templates/views/apps/appsList.ftl index 8e09b5d3..14c1e5e0 100644 --- a/maxkey-web-manage/src/main/resources/templates/views/apps/appsList.ftl +++ b/maxkey-web-manage/src/main/resources/templates/views/apps/appsList.ftl @@ -24,6 +24,7 @@ protocolArray["CAS"]="cas"; protocolArray["Basic"]="basic"; protocolArray["Desktop"]="desktop"; + protocolArray["JWT"]="jwt"; $(function () { $("#modifyApps").on("click",function(){ @@ -131,13 +132,14 @@ <@locale code="button.text.add"/> diff --git a/maxkey-web-manage/src/main/resources/templates/views/apps/jwt/appAdd.ftl b/maxkey-web-manage/src/main/resources/templates/views/apps/jwt/appAdd.ftl new file mode 100644 index 00000000..aaf6846c --- /dev/null +++ b/maxkey-web-manage/src/main/resources/templates/views/apps/jwt/appAdd.ftl @@ -0,0 +1,95 @@ + + + + <#include "../../layout/header.ftl"/> + <#include "../../layout/common.cssjs.ftl"/> + <#include "../appCommonHead.ftl"/> + + +
+ + + + + + + + + + + +
<#include "../appAddCommon.ftl"/>
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
<@locale code="apps.jwt.info" />
<@locale code="apps.jwt.redirectUri" />: + +
<@locale code="apps.jwt.tokenType" />: + + <@locale code="apps.jwt.cookieName" />: + +
<@locale code="apps.jwt.algorithm" />: + + * + <@locale code="apps.jwt.algorithmKey" />: + ${model.algorithmKey!} + + +
<@locale code="apps.jwt.content" />: + <#include "../userPropertys.ftl"/> + <@locale code="apps.jwt.expires" />: + +
+ + "/> + "/> +
+
+ + + +
+ + \ No newline at end of file diff --git a/maxkey-web-manage/src/main/resources/templates/views/apps/jwt/appUpdate.ftl b/maxkey-web-manage/src/main/resources/templates/views/apps/jwt/appUpdate.ftl new file mode 100644 index 00000000..d4146909 --- /dev/null +++ b/maxkey-web-manage/src/main/resources/templates/views/apps/jwt/appUpdate.ftl @@ -0,0 +1,95 @@ + + + + <#include "../../layout/header.ftl"/> + <#include "../../layout/common.cssjs.ftl"/> + <#include "../appCommonHead.ftl"/> + <#setting number_format="#"> + + +
+ + + + + + + + + + + +
<#include "../appUpdateCommon.ftl"/>
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
<@locale code="apps.jwt.info" />
<@locale code="apps.jwt.redirectUri" />: + +
<@locale code="apps.jwt.tokenType" />: + + <@locale code="apps.jwt.cookieName" />: + + +
<@locale code="apps.jwt.algorithm" />: + + <@locale code="apps.jwt.algorithmKey" />: + ${model.algorithmKey} + + +
<@locale code="apps.jwt.content" />: + <#include "../userPropertys.ftl"/> + <@locale code="apps.jwt.expires" />: + +
+ "/> + "/> +
+
+
+ + \ No newline at end of file diff --git a/maxkey-web-maxkey/build.gradle b/maxkey-web-maxkey/build.gradle index f63ee2ed..fd2b77e3 100644 --- a/maxkey-web-maxkey/build.gradle +++ b/maxkey-web-maxkey/build.gradle @@ -52,7 +52,7 @@ dependencies { compile project(":maxkey-protocols:maxkey-protocol-tokenbased") compile project(":maxkey-protocols:maxkey-protocol-oauth-2.0") compile project(":maxkey-protocols:maxkey-protocol-saml-2.0") - + compile project(":maxkey-protocols:maxkey-protocol-jwt") compile project(":maxkey-identitys:maxkey-identity-kafka") } diff --git a/maxkey-web-maxkey/src/main/resources/application.properties b/maxkey-web-maxkey/src/main/resources/application.properties index be21d463..e128b2d2 100644 --- a/maxkey-web-maxkey/src/main/resources/application.properties +++ b/maxkey-web-maxkey/src/main/resources/application.properties @@ -2,7 +2,7 @@ #application application.title=MaxKey application.name=MaxKey -application.formatted-version=v2.3.0 GA +application.formatted-version=v2.4.0 GA #server port #server.port=80 diff --git a/maxkey-web-maxkey/src/main/resources/templates/views/authorize/tokenbased_jwt_sso_submint.ftl b/maxkey-web-maxkey/src/main/resources/templates/views/authorize/jwt_sso_submint.ftl similarity index 100% rename from maxkey-web-maxkey/src/main/resources/templates/views/authorize/tokenbased_jwt_sso_submint.ftl rename to maxkey-web-maxkey/src/main/resources/templates/views/authorize/jwt_sso_submint.ftl diff --git a/settings.gradle b/settings.gradle index 8e205441..2ffe2c10 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,14 +15,15 @@ include 'maxkey-identitys:maxkey-identity-rest' //Protocol //include 'maxkey-protocols' +include 'maxkey-protocols:maxkey-protocol-authorize' include 'maxkey-protocols:maxkey-protocol-oauth-2.0' include 'maxkey-protocols:maxkey-protocol-saml-2.0' -include 'maxkey-protocols:maxkey-protocol-authorize' -include 'maxkey-protocols:maxkey-protocol-desktop' -include 'maxkey-protocols:maxkey-protocol-extendapi' +include 'maxkey-protocols:maxkey-protocol-cas' +include 'maxkey-protocols:maxkey-protocol-jwt' include 'maxkey-protocols:maxkey-protocol-formbased' include 'maxkey-protocols:maxkey-protocol-tokenbased' -include 'maxkey-protocols:maxkey-protocol-cas' +include 'maxkey-protocols:maxkey-protocol-extendapi' +include 'maxkey-protocols:maxkey-protocol-desktop' //include 'maxkey-webs' //maxkey