mirror of
https://gitee.com/fujieid/jap.git
synced 2024-11-30 18:47:35 +08:00
✨ Complete the development of the jap-ids module
This commit is contained in:
parent
4c072bd060
commit
c577b67266
2
jap-ids/README.md
Normal file
2
jap-ids/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
## JAP IDS
|
||||||
|
|
@ -5,14 +5,22 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.fujieid</groupId>
|
<groupId>com.fujieid</groupId>
|
||||||
<artifactId>jap</artifactId>
|
<artifactId>jap</artifactId>
|
||||||
<version>1.0.1-alpha.1</version>
|
<version>1.0.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>jap-ids</artifactId>
|
<artifactId>jap-ids</artifactId>
|
||||||
<name>jap-ids</name>
|
<name>jap-ids</name>
|
||||||
<description>
|
<description>
|
||||||
Authorization service based on rfc6749(https://tools.ietf.org/html/rfc6749) protocol specification
|
Authorization service based on RFC6749(https://tools.ietf.org/html/rfc6749) protocol specification
|
||||||
and OpenID Connect Core 1.0(https://openid.net/specs/openid-connect-core-1_0.html) specification
|
and OpenID Connect Core 1.0(https://openid.net/specs/openid-connect-core-1_0.html) specification
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fujieid</groupId>
|
||||||
|
<artifactId>jap-oidc</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@ -15,40 +15,57 @@
|
|||||||
*/
|
*/
|
||||||
package com.fujieid.jap.ids;
|
package com.fujieid.jap.ids;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.config.IdsConfig;
|
||||||
|
import com.fujieid.jap.ids.context.IdsContext;
|
||||||
|
import com.fujieid.jap.ids.exception.IdsException;
|
||||||
|
import com.fujieid.jap.ids.model.IdsConsts;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authorization service based on rfc6749 protocol specification and OpenID Connect Core 1.0 specification
|
* Authorization service based on RFC6749 protocol specification and OpenID Connect Core 1.0 specification
|
||||||
* <p>
|
|
||||||
* Features:
|
|
||||||
* <p>
|
|
||||||
* 1. Authorization Code Grant
|
|
||||||
* <p>
|
|
||||||
* 2. Implicit Grant
|
|
||||||
* <p>
|
|
||||||
* 3. Resource Owner Password Credentials Grant
|
|
||||||
* <p>
|
|
||||||
* 4. Refresh Token
|
|
||||||
* <p>
|
|
||||||
* 5. Check Token
|
|
||||||
* <p>
|
|
||||||
* 6. Proof Key for Code Exchange by OAuth Public Clients
|
|
||||||
* <p>
|
|
||||||
* 7. OpenID Connect Discovery
|
|
||||||
* <p>
|
|
||||||
* 8. OpenID Connect Front-Channel Logout
|
|
||||||
* <p>
|
|
||||||
* 9. OpenID Connect Back-Channel Logout
|
|
||||||
* <p>
|
|
||||||
* 10. ...
|
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc6749" target="_blank"> The OAuth 2.0 Authorization Framework</a>
|
|
||||||
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html" target="_blank">OpenID Connect Core 1.0 incorporating errata set 1</a>
|
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc7636" target="_blank">Proof Key for Code Exchange by OAuth Public Clients</a>
|
|
||||||
* @see <a href="https://openid.net/specs/openid-connect-discovery-1_0.html" target="_blank">OpenID Connect Discovery 1.0 incorporating errata set 1</a>
|
|
||||||
* @see <a href="https://openid.net/specs/openid-connect-frontchannel-1_0.html" target="_blank">OpenID Connect Front-Channel Logout 1.0</a>
|
|
||||||
* @see <a href="https://openid.net/specs/openid-connect-backchannel-1_0.html" target="_blank">OpenID Connect Back-Channel Logout 1.0</a>
|
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public class JapIds {
|
public class JapIds implements Serializable {
|
||||||
|
private static IdsContext context;
|
||||||
|
|
||||||
|
private JapIds() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerContext(IdsContext idsContext) {
|
||||||
|
context = idsContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IdsContext getContext() {
|
||||||
|
if (null == context) {
|
||||||
|
throw new IdsException("Unregistered ids context.Please use `JapIds.registerContext(IdsContext)` to register ids context.");
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAuthenticated(HttpServletRequest request) {
|
||||||
|
return null != getUserInfo(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveUserInfo(UserInfo userInfo, HttpServletRequest request) {
|
||||||
|
request.getSession().setAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY, userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserInfo getUserInfo(HttpServletRequest request) {
|
||||||
|
return (UserInfo) request.getSession().getAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeUserInfo(HttpServletRequest request) {
|
||||||
|
request.getSession().removeAttribute(IdsConsts.OAUTH_USERINFO_CACHE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IdsConfig getIdsConfig() {
|
||||||
|
IdsContext context = getContext();
|
||||||
|
return context.getIdsConfig();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
278
jap-ids/src/main/java/com/fujieid/jap/ids/config/IdsConfig.java
Normal file
278
jap-ids/src/main/java/com/fujieid/jap/ids/config/IdsConfig.java
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.config;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.IdsConsts;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ClientSecretAuthMethod;
|
||||||
|
import com.fujieid.jap.ids.model.enums.TokenAuthMethod;
|
||||||
|
import com.fujieid.jap.ids.util.ObjectUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ids general configuration
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user name from request through {@code request.getParameter(`usernameField`)}, which defaults to "username"
|
||||||
|
*/
|
||||||
|
private String usernameField = "username";
|
||||||
|
/**
|
||||||
|
* Get the password from request through {@code request.getParameter(`passwordField`)}, which defaults to "password"
|
||||||
|
*/
|
||||||
|
private String passwordField = "password";
|
||||||
|
/**
|
||||||
|
* Identity provider
|
||||||
|
*/
|
||||||
|
private String issuer;
|
||||||
|
/**
|
||||||
|
* Login url, the default is {@code issuer + /oauth/login}
|
||||||
|
*/
|
||||||
|
private String loginUrl;
|
||||||
|
/**
|
||||||
|
* error url
|
||||||
|
*/
|
||||||
|
private String errorUrl;
|
||||||
|
/**
|
||||||
|
* The user confirms the authorized url, the default is {@code issuer + /oauth/confirm}
|
||||||
|
*/
|
||||||
|
private String confirmUrl;
|
||||||
|
/**
|
||||||
|
* Authorized url, the default is {@code issuer + /oauth/authorize}
|
||||||
|
*/
|
||||||
|
private String authorizeUrl;
|
||||||
|
/**
|
||||||
|
* token url, the default is {@code issuer + /oauth/token}
|
||||||
|
*/
|
||||||
|
private String tokenUrl;
|
||||||
|
/**
|
||||||
|
* userinfo url, the default is {@code issuer + /oauth/userinfo}
|
||||||
|
*/
|
||||||
|
private String userinfoUrl;
|
||||||
|
/**
|
||||||
|
* Register the the client detail, the default is {@code issuer + /oauth/registration}
|
||||||
|
*/
|
||||||
|
private String registrationUrl;
|
||||||
|
/**
|
||||||
|
* logout url, the default is {@code issuer + /oauth/logout}
|
||||||
|
*/
|
||||||
|
private String endSessionUrl;
|
||||||
|
/**
|
||||||
|
* check session url, the default is {@code issuer + /oauth/check_session}
|
||||||
|
*/
|
||||||
|
private String checkSessionUrl;
|
||||||
|
/**
|
||||||
|
* After logout, redirect to {@code logoutRedirectUrl}. Default is `/`
|
||||||
|
*/
|
||||||
|
private String logoutRedirectUrl = "/";
|
||||||
|
/**
|
||||||
|
* public key url, the default is {@code issuer + /.well-known/jwks.json}
|
||||||
|
*/
|
||||||
|
private String jwksUrl;
|
||||||
|
/**
|
||||||
|
* Get open id provider metadata, the default is {@code issuer + /.well-known/openid-configuration}
|
||||||
|
*/
|
||||||
|
private String discoveryUrl;
|
||||||
|
/**
|
||||||
|
* When requesting api, the way to pass token
|
||||||
|
*/
|
||||||
|
private List<TokenAuthMethod> tokenAuthMethods = Collections.singletonList(TokenAuthMethod.ALL);
|
||||||
|
/**
|
||||||
|
* When requesting the token endpoint, the way to pass the client secret
|
||||||
|
*/
|
||||||
|
private List<ClientSecretAuthMethod> clientSecretAuthMethods = Collections.singletonList(ClientSecretAuthMethod.ALL);
|
||||||
|
/**
|
||||||
|
* Generate/verify the global configuration of jwt token.
|
||||||
|
* If the caller needs to configure a set of jwt config for each client,
|
||||||
|
* you can specify jwt config when obtaining the token.
|
||||||
|
*/
|
||||||
|
private JwtConfig jwtConfig = new JwtConfig();
|
||||||
|
|
||||||
|
public IdsConfig(String issuer) {
|
||||||
|
this.issuer = issuer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsernameField() {
|
||||||
|
return usernameField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setUsernameField(String usernameField) {
|
||||||
|
this.usernameField = usernameField;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPasswordField() {
|
||||||
|
return passwordField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setPasswordField(String passwordField) {
|
||||||
|
this.passwordField = passwordField;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIssuer() {
|
||||||
|
return issuer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setIssuer(String issuer) {
|
||||||
|
this.issuer = issuer;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLoginUrl() {
|
||||||
|
return null == loginUrl ? ObjectUtils.appendIfNotEndWith(issuer, IdsConsts.SLASH) + "oauth/login" : loginUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setLoginUrl(String loginUrl) {
|
||||||
|
this.loginUrl = loginUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorUrl() {
|
||||||
|
return errorUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setErrorUrl(String errorUrl) {
|
||||||
|
this.errorUrl = errorUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConfirmUrl() {
|
||||||
|
return null == confirmUrl ? ObjectUtils.appendIfNotEndWith(issuer, IdsConsts.SLASH) + "oauth/confirm" : confirmUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setConfirmUrl(String confirmUrl) {
|
||||||
|
this.confirmUrl = confirmUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthorizeUrl() {
|
||||||
|
return null == authorizeUrl ? ObjectUtils.appendIfNotEndWith(issuer, IdsConsts.SLASH) + "oauth/authorize" : authorizeUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setAuthorizeUrl(String authorizeUrl) {
|
||||||
|
this.authorizeUrl = authorizeUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTokenUrl() {
|
||||||
|
return null == tokenUrl ? ObjectUtils.appendIfNotEndWith(issuer, IdsConsts.SLASH) + "oauth/token" : tokenUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setTokenUrl(String tokenUrl) {
|
||||||
|
this.tokenUrl = tokenUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserinfoUrl() {
|
||||||
|
return null == userinfoUrl ? ObjectUtils.appendIfNotEndWith(issuer, IdsConsts.SLASH) + "oauth/userinfo" : userinfoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setUserinfoUrl(String userinfoUrl) {
|
||||||
|
this.userinfoUrl = userinfoUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegistrationUrl() {
|
||||||
|
return null == registrationUrl ? ObjectUtils.appendIfNotEndWith(issuer, IdsConsts.SLASH) + "oauth/registration" : registrationUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setRegistrationUrl(String registrationUrl) {
|
||||||
|
this.registrationUrl = registrationUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEndSessionUrl() {
|
||||||
|
return null == endSessionUrl ? ObjectUtils.appendIfNotEndWith(issuer, IdsConsts.SLASH) + "oauth/logout" : endSessionUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setEndSessionUrl(String endSessionUrl) {
|
||||||
|
this.endSessionUrl = endSessionUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCheckSessionUrl() {
|
||||||
|
return null == checkSessionUrl ? ObjectUtils.appendIfNotEndWith(issuer, IdsConsts.SLASH) + "oauth/check_session" : checkSessionUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setCheckSessionUrl(String checkSessionUrl) {
|
||||||
|
this.checkSessionUrl = checkSessionUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLogoutRedirectUrl() {
|
||||||
|
return logoutRedirectUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setLogoutRedirectUrl(String logoutRedirectUrl) {
|
||||||
|
this.logoutRedirectUrl = logoutRedirectUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJwksUrl() {
|
||||||
|
return null == jwksUrl ? ObjectUtils.appendIfNotEndWith(issuer, IdsConsts.SLASH) + ".well-known/jwks.json" : jwksUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setJwksUrl(String jwksUrl) {
|
||||||
|
this.jwksUrl = jwksUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDiscoveryUrl() {
|
||||||
|
return null == discoveryUrl ? ObjectUtils.appendIfNotEndWith(issuer, IdsConsts.SLASH) + ".well-known/openid-configuration" : discoveryUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setDiscoveryUrl(String discoveryUrl) {
|
||||||
|
this.discoveryUrl = discoveryUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtConfig getJwtConfig() {
|
||||||
|
return null == jwtConfig ? new JwtConfig() : jwtConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setJwtConfig(JwtConfig jwtConfig) {
|
||||||
|
this.jwtConfig = jwtConfig;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TokenAuthMethod> getTokenAuthMethods() {
|
||||||
|
return tokenAuthMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setTokenAuthMethods(List<TokenAuthMethod> tokenAuthMethods) {
|
||||||
|
this.tokenAuthMethods = tokenAuthMethods;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClientSecretAuthMethod> getClientSecretAuthMethods() {
|
||||||
|
return clientSecretAuthMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig setClientSecretAuthMethods(List<ClientSecretAuthMethod> clientSecretAuthMethods) {
|
||||||
|
this.clientSecretAuthMethods = clientSecretAuthMethods;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.config;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.JwtVerificationType;
|
||||||
|
import com.fujieid.jap.ids.model.enums.TokenSigningAlg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate/verify the global configuration of jwt token.
|
||||||
|
* If the caller needs to configure a set of jwt config for each client,
|
||||||
|
* you can specify jwt config when obtaining the token.
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class JwtConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rsa encryption key id
|
||||||
|
*/
|
||||||
|
private String jwksKeyId = "jap-jwk-keyid";
|
||||||
|
/**
|
||||||
|
* <strong>Optional</strong>, jwt token verification type, the default is {@code JwtVerificationType.HTTPS_JWKS_ENDPOINT}
|
||||||
|
* <p>
|
||||||
|
* The usage is as follows:
|
||||||
|
* <p>
|
||||||
|
* 1. If the public key of the jwt issuer is at the https jwks endpoint, please set it to {@code JwtVerificationType.HTTPS_JWKS_ENDPOINT}
|
||||||
|
* <p>
|
||||||
|
* 2. When using jwks certificate string verification, please set it to {@code JwtVerificationType.JWKS}
|
||||||
|
* <p>
|
||||||
|
* 3. When using x.509 certificate string verification, please set it to {@code JwtVerificationType.X_509}
|
||||||
|
*/
|
||||||
|
private JwtVerificationType jwtVerificationType = JwtVerificationType.HTTPS_JWKS_ENDPOINT;
|
||||||
|
/**
|
||||||
|
* <strong>Optional</strong>, when {@link JwtConfig#jwtVerificationType} is equal to {@code JWKS}, this attribute is <strong>required</strong>
|
||||||
|
*/
|
||||||
|
private String jwksJson;
|
||||||
|
/**
|
||||||
|
* jwt token encryption algorithm, the default is {@code RS256}
|
||||||
|
*/
|
||||||
|
private TokenSigningAlg tokenSigningAlg = TokenSigningAlg.RS256;
|
||||||
|
|
||||||
|
public JwtVerificationType getJwtVerificationType() {
|
||||||
|
return jwtVerificationType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtConfig setJwtVerificationType(JwtVerificationType jwtVerificationType) {
|
||||||
|
this.jwtVerificationType = jwtVerificationType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJwksKeyId() {
|
||||||
|
return jwksKeyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtConfig setJwksKeyId(String jwksKeyId) {
|
||||||
|
this.jwksKeyId = jwksKeyId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJwksJson() {
|
||||||
|
return jwksJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtConfig setJwksJson(String jwksJson) {
|
||||||
|
this.jwksJson = jwksJson;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenSigningAlg getTokenSigningAlg() {
|
||||||
|
return tokenSigningAlg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtConfig setTokenSigningAlg(TokenSigningAlg tokenSigningAlg) {
|
||||||
|
this.tokenSigningAlg = tokenSigningAlg;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* IDS config
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
package com.fujieid.jap.ids.config;
|
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.context;
|
||||||
|
|
||||||
|
import com.fujieid.jap.core.cache.JapCache;
|
||||||
|
import com.fujieid.jap.core.cache.JapLocalCache;
|
||||||
|
import com.fujieid.jap.ids.config.IdsConfig;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
import com.fujieid.jap.ids.service.IdsClientDetailService;
|
||||||
|
import com.fujieid.jap.ids.service.IdsIdentityService;
|
||||||
|
import com.fujieid.jap.ids.service.IdsUserService;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ids context
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsContext implements Serializable {
|
||||||
|
|
||||||
|
private JapCache cache = new JapLocalCache();
|
||||||
|
|
||||||
|
private IdsClientDetailService clientDetailService;
|
||||||
|
|
||||||
|
private IdsUserService userService;
|
||||||
|
|
||||||
|
private IdsIdentityService identityService;
|
||||||
|
|
||||||
|
private IdsConfig idsConfig;
|
||||||
|
|
||||||
|
public JapCache getCache() {
|
||||||
|
return cache == null ? new JapLocalCache() : cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsContext setCache(JapCache cache) {
|
||||||
|
this.cache = cache;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsClientDetailService getClientDetailService() {
|
||||||
|
return clientDetailService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsContext setClientDetailService(IdsClientDetailService clientDetailService) {
|
||||||
|
this.clientDetailService = clientDetailService;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsUserService getUserService() {
|
||||||
|
return userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsContext setUserService(IdsUserService userService) {
|
||||||
|
this.userService = userService;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsConfig getIdsConfig() {
|
||||||
|
return idsConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsContext setIdsConfig(IdsConfig idsConfig) {
|
||||||
|
this.idsConfig = idsConfig;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsIdentityService getIdentityService() {
|
||||||
|
return identityService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsContext setIdentityService(IdsIdentityService identityService) {
|
||||||
|
this.identityService = identityService;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* IDS context
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
package com.fujieid.jap.ids.context;
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.endpoint;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.config.IdsConfig;
|
||||||
|
import com.fujieid.jap.ids.service.Oauth2Service;
|
||||||
|
import com.fujieid.jap.ids.service.Oauth2ServiceImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract classes common to various endpoints
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public abstract class AbstractEndpoint {
|
||||||
|
protected final Oauth2Service oauth2Service;
|
||||||
|
protected IdsConfig idsConfig;
|
||||||
|
|
||||||
|
public AbstractEndpoint() {
|
||||||
|
this.idsConfig = JapIds.getIdsConfig();
|
||||||
|
this.oauth2Service = new Oauth2ServiceImpl();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.endpoint;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidClientException;
|
||||||
|
import com.fujieid.jap.ids.model.ClientDetail;
|
||||||
|
import com.fujieid.jap.ids.model.IdsRequestParam;
|
||||||
|
import com.fujieid.jap.ids.model.IdsResponse;
|
||||||
|
import com.fujieid.jap.ids.model.IdsScope;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.provider.IdsRequestParamProvider;
|
||||||
|
import com.fujieid.jap.ids.provider.IdsScopeProvider;
|
||||||
|
import com.fujieid.jap.ids.util.OauthUtil;
|
||||||
|
import com.fujieid.jap.ids.util.ObjectUtils;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm authorization endpoint
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class ApprovalEndpoint extends AbstractEndpoint {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default authorization confirmation page pops up
|
||||||
|
*
|
||||||
|
* @param request Current request
|
||||||
|
* @param response Current response
|
||||||
|
* @throws IOException IOException
|
||||||
|
*/
|
||||||
|
public void confirm(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
final String approvalContent = createConfirmPageHtml(request);
|
||||||
|
response.setContentType("text/html;charset=UTF-8");
|
||||||
|
response.getWriter().append(approvalContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain authorization information when you jump to the authorization confirmation page after successful login
|
||||||
|
*
|
||||||
|
* @param request HttpServletRequest
|
||||||
|
* @return IdsResponse
|
||||||
|
*/
|
||||||
|
public IdsResponse<String, Object> getAuthClientInfo(HttpServletRequest request) {
|
||||||
|
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||||
|
// Verify client application
|
||||||
|
if (StringUtil.isEmpty(param.getClientId())) {
|
||||||
|
throw new InvalidClientException(ErrorResponse.INVALID_CLIENT);
|
||||||
|
}
|
||||||
|
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId());
|
||||||
|
List<Map<String, Object>> scopeInfo = getScopeInfo(param);
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(5);
|
||||||
|
result.put("appInfo", clientDetail);
|
||||||
|
result.put("scopes", scopeInfo);
|
||||||
|
result.put("params", param);
|
||||||
|
|
||||||
|
return new IdsResponse<String, Object>().data(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the html of the authorization confirmation page
|
||||||
|
*
|
||||||
|
* @param request Current request
|
||||||
|
* @return Confirm the html of the authorization page
|
||||||
|
*/
|
||||||
|
private String createConfirmPageHtml(HttpServletRequest request) {
|
||||||
|
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||||
|
String clientId = param.getClientId();
|
||||||
|
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(clientId);
|
||||||
|
OauthUtil.validClientDetail(clientDetail);
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
String html = "<!DOCTYPE html>\n"
|
||||||
|
+ "<html lang=\"en\">\n"
|
||||||
|
+ " <head>\n"
|
||||||
|
+ " <meta charset=\"utf-8\">\n"
|
||||||
|
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
|
||||||
|
+ " <meta name=\"description\" content=\"\">\n"
|
||||||
|
+ " <meta name=\"author\" content=\"\">\n"
|
||||||
|
+ " <title>OAuth Approval</title>\n"
|
||||||
|
+ " </head>\n"
|
||||||
|
+ " \n";
|
||||||
|
builder.append(html).append("<body><h1>OAuth Approval</h1>");
|
||||||
|
builder.append("<p>Do you authorize \"<strong>").append(clientDetail.getAppName()).append("</strong>");
|
||||||
|
builder.append(" (").append(clientId).append(")");
|
||||||
|
builder.append("\" to access your protected resources?</p>");
|
||||||
|
builder.append("<form id=\"confirmationForm\" name=\"confirmationForm\" action=\"");
|
||||||
|
|
||||||
|
String requestPath = ObjectUtils.appendIfNotEndWith(JapIds.getIdsConfig().getAuthorizeUrl(), "?") + request.getQueryString();
|
||||||
|
builder.append(requestPath).append("\" method=\"post\">");
|
||||||
|
builder.append("<input name=\"user_oauth_approval\" value=\"true\" type=\"hidden\"/>");
|
||||||
|
|
||||||
|
String authorizeInputTemplate = "<label><input name=\"authorize\" value=\"Authorize\" type=\"submit\"/></label></form>";
|
||||||
|
|
||||||
|
if (param.getScope() != null) {
|
||||||
|
builder.append(createScopes(param, request));
|
||||||
|
builder.append(authorizeInputTemplate);
|
||||||
|
} else {
|
||||||
|
builder.append(authorizeInputTemplate);
|
||||||
|
builder.append("<form id=\"denialForm\" name=\"denialForm\" action=\"");
|
||||||
|
builder.append(requestPath).append("/oauth/authorize\" method=\"post\">");
|
||||||
|
builder.append("<input name=\"user_oauth_approval\" value=\"false\" type=\"hidden\"/>");
|
||||||
|
builder.append("<label><input name=\"deny\" value=\"Deny\" type=\"submit\"/></label></form>");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.append("</body></html>");
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the scope list of the authorization confirmation page
|
||||||
|
*
|
||||||
|
* @param param Parameters of the current request
|
||||||
|
* @param request Current request
|
||||||
|
* @return the scope list of the authorization confirmation page
|
||||||
|
*/
|
||||||
|
private String createScopes(IdsRequestParam param, HttpServletRequest request) {
|
||||||
|
StringBuilder builder = new StringBuilder("<ul style=\"list-style: none;padding-inline-start: 20px;\">");
|
||||||
|
List<Map<String, Object>> scopeInfo = getScopeInfo(param);
|
||||||
|
|
||||||
|
for (Map<String, Object> scope : scopeInfo) {
|
||||||
|
String approved = (Boolean) scope.get("selected") ? " checked" : "";
|
||||||
|
String denied = (Boolean) scope.get("selected") ? "" : " checked";
|
||||||
|
|
||||||
|
builder.append("<li><div class=\"form-group\">");
|
||||||
|
builder.append("<input type=\"checkbox\" name=\"scopes\"").append(" value=\"").append(scope.get("code")).append("\"").append(approved).append(" style=\"margin-right: 5px;\">")
|
||||||
|
.append(scope.get("code")).append(" - ").append(scope.get("description"))
|
||||||
|
.append("</input> ");
|
||||||
|
builder.append(denied).append("</div></li>");
|
||||||
|
}
|
||||||
|
builder.append("</ul>");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorganize scope information
|
||||||
|
*
|
||||||
|
* @param param Parameters of the current request
|
||||||
|
* @return List
|
||||||
|
*/
|
||||||
|
private List<Map<String, Object>> getScopeInfo(IdsRequestParam param) {
|
||||||
|
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId());
|
||||||
|
OauthUtil.validClientDetail(clientDetail);
|
||||||
|
Set<String> userAuthorizedScopes = OauthUtil.validateScope(param.getScope(), clientDetail.getScopes());
|
||||||
|
|
||||||
|
Set<String> supportedScopes = OauthUtil.convertStrToList(clientDetail.getScopes());
|
||||||
|
|
||||||
|
List<IdsScope> scopeList = IdsScopeProvider.getScopeByCodes(supportedScopes);
|
||||||
|
|
||||||
|
List<Map<String, Object>> scopeInfo = new LinkedList<>();
|
||||||
|
Map<String, Object> scopeItem = null;
|
||||||
|
for (IdsScope idsScope : scopeList) {
|
||||||
|
scopeItem = new HashMap<>(5);
|
||||||
|
scopeItem.put("code", idsScope.getCode());
|
||||||
|
scopeItem.put("description", idsScope.getDescription());
|
||||||
|
scopeItem.put("selected", userAuthorizedScopes.contains(idsScope.getCode()));
|
||||||
|
scopeInfo.add(scopeItem);
|
||||||
|
}
|
||||||
|
return scopeInfo;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.endpoint;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidScopeException;
|
||||||
|
import com.fujieid.jap.ids.model.ClientDetail;
|
||||||
|
import com.fujieid.jap.ids.model.IdsRequestParam;
|
||||||
|
import com.fujieid.jap.ids.model.IdsResponse;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ResponseType;
|
||||||
|
import com.fujieid.jap.ids.provider.IdsAuthorizationProvider;
|
||||||
|
import com.fujieid.jap.ids.provider.IdsRequestParamProvider;
|
||||||
|
import com.fujieid.jap.ids.util.OauthUtil;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorization endpoint
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class AuthorizationEndpoint extends AbstractEndpoint {
|
||||||
|
|
||||||
|
private final IdsAuthorizationProvider idsAuthorizationProvider = new IdsAuthorizationProvider(oauth2Service);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorize current request
|
||||||
|
* <p>
|
||||||
|
* When logged in, the method returns the callback url (with parameters such as code)
|
||||||
|
* <p>
|
||||||
|
* When not logged in, the method returns the login url (with the parameters of the current request)
|
||||||
|
*
|
||||||
|
* @param request Current request
|
||||||
|
* @return Callback url or authorization url
|
||||||
|
* @throws IOException IOException
|
||||||
|
*/
|
||||||
|
public IdsResponse<String, Object> authorize(HttpServletRequest request) throws IOException {
|
||||||
|
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||||
|
|
||||||
|
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId());
|
||||||
|
|
||||||
|
OauthUtil.validClientDetail(clientDetail);
|
||||||
|
OauthUtil.validateResponseType(param.getResponseType(), clientDetail.getResponseTypes());
|
||||||
|
OauthUtil.validateRedirectUri(param.getRedirectUri(), clientDetail);
|
||||||
|
OauthUtil.validateScope(param.getScope(), clientDetail.getScopes());
|
||||||
|
|
||||||
|
if (JapIds.isAuthenticated(request)) {
|
||||||
|
UserInfo userInfo = JapIds.getUserInfo(request);
|
||||||
|
String url = generateResponseUrl(param, param.getResponseType(), clientDetail, userInfo);
|
||||||
|
return new IdsResponse<String, Object>().data(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IdsResponse<String, Object>()
|
||||||
|
.data(OauthUtil.createAuthorizeUrl(idsConfig.getLoginUrl(), param));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User-initiated consent authorization
|
||||||
|
*
|
||||||
|
* @param request current request
|
||||||
|
* @return Return the callback url (with parameters such as code)
|
||||||
|
*/
|
||||||
|
public IdsResponse<String, Object> agree(HttpServletRequest request) {
|
||||||
|
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||||
|
|
||||||
|
// The scope checked by the user may be inconsistent with the scope passed in the current request
|
||||||
|
String[] requestScopes = request.getParameterValues("scopes");
|
||||||
|
Set<String> scopes = null;
|
||||||
|
if (ArrayUtil.isEmpty(requestScopes)) {
|
||||||
|
if (StringUtil.isEmpty(param.getScope())) {
|
||||||
|
throw new InvalidScopeException(ErrorResponse.INVALID_SCOPE);
|
||||||
|
}
|
||||||
|
scopes = OauthUtil.convertStrToList(param.getScope()).stream().distinct().collect(Collectors.toSet());
|
||||||
|
} else {
|
||||||
|
scopes = new TreeSet<>(Arrays.asList(requestScopes));
|
||||||
|
}
|
||||||
|
// Ultimately participating in the authorized scope
|
||||||
|
param.setScope(String.join(" ", scopes));
|
||||||
|
|
||||||
|
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId());
|
||||||
|
OauthUtil.validClientDetail(clientDetail);
|
||||||
|
|
||||||
|
String responseType = param.getResponseType();
|
||||||
|
UserInfo userInfo = JapIds.getUserInfo(request);
|
||||||
|
String url = generateResponseUrl(param, responseType, clientDetail, userInfo);
|
||||||
|
return new IdsResponse<String, Object>().data(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate callback url
|
||||||
|
*
|
||||||
|
* @param param Parameters in the current request
|
||||||
|
* @param responseType oauth authorized response type
|
||||||
|
* @param clientDetail Currently authorized client
|
||||||
|
* @return Callback url
|
||||||
|
*/
|
||||||
|
private String generateResponseUrl(IdsRequestParam param, String responseType, ClientDetail clientDetail, UserInfo userInfo) {
|
||||||
|
if (ResponseType.CODE.getType().equalsIgnoreCase(responseType)) {
|
||||||
|
return idsAuthorizationProvider.generateAuthorizationCodeResponse(userInfo, param, clientDetail);
|
||||||
|
}
|
||||||
|
if (ResponseType.TOKEN.getType().equalsIgnoreCase(responseType)) {
|
||||||
|
return idsAuthorizationProvider.generateImplicitGrantResponse(userInfo, param, clientDetail);
|
||||||
|
}
|
||||||
|
if (ResponseType.ID_TOKEN.getType().equalsIgnoreCase(responseType)) {
|
||||||
|
return idsAuthorizationProvider.generateIdTokenAuthorizationResponse(userInfo, param, clientDetail);
|
||||||
|
}
|
||||||
|
if (ResponseType.ID_TOKEN_TOKEN.getType().equalsIgnoreCase(responseType)) {
|
||||||
|
return idsAuthorizationProvider.generateIdTokenTokenAuthorizationResponse(userInfo, param, clientDetail);
|
||||||
|
}
|
||||||
|
if (ResponseType.CODE_ID_TOKEN.getType().equalsIgnoreCase(responseType)) {
|
||||||
|
return idsAuthorizationProvider.generateCodeIdTokenAuthorizationResponse(userInfo, param, clientDetail);
|
||||||
|
}
|
||||||
|
if (ResponseType.CODE_TOKEN.getType().equalsIgnoreCase(responseType)) {
|
||||||
|
return idsAuthorizationProvider.generateCodeTokenAuthorizationResponse(userInfo, param, clientDetail);
|
||||||
|
}
|
||||||
|
if (ResponseType.CODE_ID_TOKEN_TOKEN.getType().equalsIgnoreCase(responseType)) {
|
||||||
|
return idsAuthorizationProvider.generateCodeIdTokenTokenAuthorizationResponse(userInfo, param, clientDetail);
|
||||||
|
}
|
||||||
|
// none
|
||||||
|
return idsAuthorizationProvider.generateNoneAuthorizationResponse(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.endpoint;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.OidcDiscoveryDto;
|
||||||
|
import com.fujieid.jap.ids.oidc.OidcUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenID Provider Endpoint
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @see <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata" target="_blank">OpenID Provider Metadata</a>
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class DiscoveryEndpoint extends AbstractEndpoint {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenID Provider Configuration Response.
|
||||||
|
* <p>
|
||||||
|
* For multiple users (can be users, organizations, enterprises, etc.), different configurations can be generated through {@code identity}.
|
||||||
|
* <p>
|
||||||
|
* Such as the following scenario:
|
||||||
|
* <p>
|
||||||
|
* The issuer of idp is `http://localhost`, and the api in the idp is distinguished according to the user ID.
|
||||||
|
* <p>
|
||||||
|
* When {@code identity} is not empty, take the token endpoint as an example. The endpoint generated by this method is actually `http://localhost/oauth/token/{identity}`
|
||||||
|
*
|
||||||
|
* @param identity identity
|
||||||
|
* @return OpenID Provider Configuration
|
||||||
|
* @see <a href="https://tools.ietf.org/html/draft-ietf-oauth-discovery-06">https://tools.ietf.org/html/draft-ietf-oauth-discovery-06</a>
|
||||||
|
* @see <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata" target="_blank">OpenID Provider Metadata</a>
|
||||||
|
* @see <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest">OpenID Provider Configuration Response</a>
|
||||||
|
*/
|
||||||
|
public OidcDiscoveryDto getOidcDiscoveryInfo(String identity) {
|
||||||
|
return OidcUtil.getOidcDiscoveryInfo(identity, idsConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the public key of the encrypted token (can be used to decrypt the token)
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For multiple users (can be users, organizations, enterprises, etc.), The public key information of different users can be obtained through {@code identity}.
|
||||||
|
* <p>
|
||||||
|
* Such as the following scenario:
|
||||||
|
* <p>
|
||||||
|
* Different users are assigned different keys in the idp system. When the {@code identity} is not empty,
|
||||||
|
* <p>
|
||||||
|
* the method will first obtain the user's certificate through the {@code identity}, and then generate the public key through the certificate
|
||||||
|
*
|
||||||
|
* @param identity identity
|
||||||
|
* @return public key
|
||||||
|
*/
|
||||||
|
public String getJwksPublicKey(String identity) {
|
||||||
|
return OidcUtil.getJwksPublicKey(identity, idsConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.endpoint;
|
||||||
|
|
||||||
|
import com.fujieid.jap.core.util.RequestUtil;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth 异常
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class ErrorEndpoint extends AbstractEndpoint {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the html of the error authorization page
|
||||||
|
*
|
||||||
|
* @param error error type
|
||||||
|
* @param errorDescription error description
|
||||||
|
* @return error page html
|
||||||
|
*/
|
||||||
|
public String createErrorPageHtml(String error, String errorDescription) {
|
||||||
|
return generateErrorPageHtml(error, errorDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain exception information from the request url and display the exception page
|
||||||
|
*
|
||||||
|
* @param request Current request
|
||||||
|
* @param response Current response
|
||||||
|
* @throws IOException IOException
|
||||||
|
*/
|
||||||
|
public void showErrorPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
ErrorResponse errorResponse = ErrorResponse.getByError(RequestUtil.getParam("error", request));
|
||||||
|
String errorPageHtml = createErrorPageHtml(errorResponse.getError(), errorResponse.getErrorDescription());
|
||||||
|
response.setContentType("text/html;charset=UTF-8");
|
||||||
|
response.setContentLength(errorPageHtml.getBytes(StandardCharsets.UTF_8).length);
|
||||||
|
response.getWriter().write(errorPageHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display customized exception content
|
||||||
|
*
|
||||||
|
* @param error error type
|
||||||
|
* @param errorDescription error description
|
||||||
|
* @param response Current response
|
||||||
|
* @throws IOException IOException
|
||||||
|
*/
|
||||||
|
public void showErrorPage(String error, String errorDescription, HttpServletResponse response) throws IOException {
|
||||||
|
String errorPageHtml = createErrorPageHtml(error, errorDescription);
|
||||||
|
response.setContentType("text/html;charset=UTF-8");
|
||||||
|
response.setContentLength(errorPageHtml.getBytes(StandardCharsets.UTF_8).length);
|
||||||
|
response.getWriter().write(errorPageHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String generateErrorPageHtml(String error, String errorDescription) {
|
||||||
|
String html = "<!DOCTYPE html>\n"
|
||||||
|
+ "<html lang=\"en\">\n"
|
||||||
|
+ " <head>\n"
|
||||||
|
+ " <meta charset=\"utf-8\">\n"
|
||||||
|
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
|
||||||
|
+ " <meta name=\"description\" content=\"\">\n"
|
||||||
|
+ " <meta name=\"author\" content=\"\">\n"
|
||||||
|
+ " <title>Oops!, something went wrong</title>\n"
|
||||||
|
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
|
||||||
|
+ " </head>\n"
|
||||||
|
+ " <body>\n"
|
||||||
|
+ " <div class=\"container text-center\" style=\"margin-top: 10%;\">\n"
|
||||||
|
+ " <p><h1>Oops!, something went wrong</h1></p>\n";
|
||||||
|
if (StringUtil.isNotEmpty(error)) {
|
||||||
|
html += "<p>" + error + "</p>";
|
||||||
|
}
|
||||||
|
html += " <p>\n" + errorDescription + " </p>\n"
|
||||||
|
+ " <p>Feel free to contact us.</p>\n"
|
||||||
|
+ " <p>Please try again.</p>\n" +
|
||||||
|
"</div>\n" +
|
||||||
|
"</body></html>";
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.endpoint;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.exception.IdsException;
|
||||||
|
import com.fujieid.jap.ids.model.IdsResponse;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.util.ObjectUtils;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login Endpoint
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class LoginEndpoint extends AbstractEndpoint {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示默认的登录页面
|
||||||
|
*
|
||||||
|
* @param request current request
|
||||||
|
* @param response current response
|
||||||
|
* @throws IOException IOException
|
||||||
|
*/
|
||||||
|
public void showLoginPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
String loginPageHtml = generateLoginPageHtml(request);
|
||||||
|
response.setContentType("text/html;charset=UTF-8");
|
||||||
|
response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length);
|
||||||
|
response.getWriter().write(loginPageHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateLoginPageHtml(HttpServletRequest request) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("<!DOCTYPE html>\n"
|
||||||
|
+ "<html lang=\"en\">\n"
|
||||||
|
+ " <head>\n"
|
||||||
|
+ " <meta charset=\"utf-8\">\n"
|
||||||
|
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
|
||||||
|
+ " <meta name=\"description\" content=\"\">\n"
|
||||||
|
+ " <meta name=\"author\" content=\"\">\n"
|
||||||
|
+ " <title>Please sign in</title>\n"
|
||||||
|
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
|
||||||
|
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
|
||||||
|
+ " </head>\n"
|
||||||
|
+ " <body>\n"
|
||||||
|
+ " <div class=\"container\">\n");
|
||||||
|
|
||||||
|
String authenticationUrl = ObjectUtils.appendIfNotEndWith(JapIds.getIdsConfig().getLoginUrl(), "?") + request.getQueryString();
|
||||||
|
sb.append(" <form class=\"form-signin\" method=\"post\" action=\"").append(authenticationUrl).append("\">\n")
|
||||||
|
.append(" <h2 class=\"form-signin-heading\">Please sign in</h2>\n")
|
||||||
|
.append(" <p>\n")
|
||||||
|
.append(" <label for=\"username\" class=\"sr-only\">Username</label>\n")
|
||||||
|
.append(" <input type=\"text\" id=\"username\" name=\"").append(JapIds.getIdsConfig().getUsernameField())
|
||||||
|
.append("\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n").append(" </p>\n")
|
||||||
|
.append(" <p>\n").append(" <label for=\"password\" class=\"sr-only\">Password</label>\n")
|
||||||
|
.append(" <input type=\"password\" id=\"password\" name=\"")
|
||||||
|
.append(JapIds.getIdsConfig().getPasswordField()).append("\" class=\"form-control\" placeholder=\"Password\" required>\n")
|
||||||
|
.append(" </p>\n").append(" <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n")
|
||||||
|
.append(" </form>\n");
|
||||||
|
|
||||||
|
sb.append("</div>\n");
|
||||||
|
sb.append("</body></html>");
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login with account password
|
||||||
|
*
|
||||||
|
* @param request current request
|
||||||
|
* @return Confirm authorization page
|
||||||
|
*/
|
||||||
|
public IdsResponse<String, Object> signin(HttpServletRequest request) {
|
||||||
|
String username = request.getParameter(idsConfig.getUsernameField());
|
||||||
|
String password = request.getParameter(idsConfig.getPasswordField());
|
||||||
|
if (ObjectUtil.hasEmpty(username, password)) {
|
||||||
|
throw new IdsException(ErrorResponse.INVALID_USER_CERTIFICATE);
|
||||||
|
}
|
||||||
|
UserInfo userInfo = JapIds.getContext().getUserService().loginByUsernameAndPassword(username, password);
|
||||||
|
if (null == userInfo) {
|
||||||
|
throw new IdsException(ErrorResponse.INVALID_USER_CERTIFICATE);
|
||||||
|
}
|
||||||
|
JapIds.saveUserInfo(userInfo, request);
|
||||||
|
|
||||||
|
return new IdsResponse<String, Object>()
|
||||||
|
.data(ObjectUtils.appendIfNotEndWith(JapIds.getIdsConfig().getConfirmUrl(), "?") + request.getQueryString());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.endpoint;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.model.IdsResponse;
|
||||||
|
import com.fujieid.jap.ids.util.TokenUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logout Endpoint
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class LogoutEndpoint extends AbstractEndpoint {
|
||||||
|
|
||||||
|
public IdsResponse<String, Object> logout(HttpServletRequest request) {
|
||||||
|
JapIds.removeUserInfo(request);
|
||||||
|
TokenUtil.invalidateToken(request);
|
||||||
|
request.getSession().invalidate();
|
||||||
|
return new IdsResponse<String, Object>()
|
||||||
|
.data(idsConfig.getLogoutRedirectUrl());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.endpoint;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.exception.UnsupportedGrantTypeException;
|
||||||
|
import com.fujieid.jap.ids.model.IdsRequestParam;
|
||||||
|
import com.fujieid.jap.ids.model.IdsResponse;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.model.enums.GrantType;
|
||||||
|
import com.fujieid.jap.ids.provider.IdsRequestParamProvider;
|
||||||
|
import com.fujieid.jap.ids.provider.IdsTokenProvider;
|
||||||
|
import com.fujieid.jap.ids.util.JwtUtil;
|
||||||
|
import com.fujieid.jap.ids.util.TokenUtil;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token Endpoint. According to the request parameters, to obtain different types of access tokens, refer to:
|
||||||
|
* <p>
|
||||||
|
* https://tools.ietf.org/html/rfc6749#section-5
|
||||||
|
* <p>
|
||||||
|
* https://tools.ietf.org/html/rfc6749#section-6
|
||||||
|
* <p>
|
||||||
|
* The OAuth 2.0 Authorization Framework: Bearer Token Usage: https://tools.ietf.org/html/rfc6750
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class TokenEndpoint extends AbstractEndpoint {
|
||||||
|
|
||||||
|
private final IdsTokenProvider idsTokenProvider = new IdsTokenProvider(oauth2Service);
|
||||||
|
|
||||||
|
public IdsResponse<String, Object> getToken(HttpServletRequest request) {
|
||||||
|
IdsRequestParam param = IdsRequestParamProvider.parseRequest(request);
|
||||||
|
|
||||||
|
if (StringUtil.isEmpty(param.getGrantType())) {
|
||||||
|
throw new UnsupportedGrantTypeException(ErrorResponse.UNSUPPORTED_GRANT_TYPE);
|
||||||
|
}
|
||||||
|
if (GrantType.AUTHORIZATION_CODE.getType().equals(param.getGrantType())) {
|
||||||
|
return idsTokenProvider.generateAuthorizationCodeResponse(param);
|
||||||
|
}
|
||||||
|
if (GrantType.PASSWORD.getType().equals(param.getGrantType())) {
|
||||||
|
return idsTokenProvider.generatePasswordResponse(param);
|
||||||
|
}
|
||||||
|
if (GrantType.CLIENT_CREDENTIALS.getType().equals(param.getGrantType())) {
|
||||||
|
return idsTokenProvider.generateClientCredentialsResponse(param);
|
||||||
|
}
|
||||||
|
if (GrantType.REFRESH_TOKEN.getType().equals(param.getGrantType())) {
|
||||||
|
return idsTokenProvider.generateRefreshTokenResponse(param);
|
||||||
|
}
|
||||||
|
throw new UnsupportedGrantTypeException(ErrorResponse.UNSUPPORTED_GRANT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsResponse<String, Object> checkToken(String token) {
|
||||||
|
return new IdsResponse<String, Object>()
|
||||||
|
.addAll(JwtUtil.parseJwtToken(token, JapIds.getIdsConfig()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsResponse<String, Object> revokeToken(HttpServletRequest request) {
|
||||||
|
TokenUtil.invalidateToken(request);
|
||||||
|
return new IdsResponse<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.endpoint;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.exception.IdsException;
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidTokenException;
|
||||||
|
import com.fujieid.jap.ids.model.AccessToken;
|
||||||
|
import com.fujieid.jap.ids.model.IdsResponse;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.util.TokenUtil;
|
||||||
|
import com.xkcoding.json.JsonUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* userinfo endpoint
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class UserInfoEndpoint extends AbstractEndpoint {
|
||||||
|
|
||||||
|
public IdsResponse<String, Object> getCurrentUserInfo(HttpServletRequest request) {
|
||||||
|
|
||||||
|
String accessTokenStr = TokenUtil.getAccessToken(request);
|
||||||
|
|
||||||
|
AccessToken accessToken = TokenUtil.getByAccessToken(accessTokenStr);
|
||||||
|
|
||||||
|
if (null == accessToken) {
|
||||||
|
throw new InvalidTokenException(ErrorResponse.INVALID_TOKEN);
|
||||||
|
}
|
||||||
|
UserInfo user = JapIds.getContext().getUserService().getById(accessToken.getUserId());
|
||||||
|
|
||||||
|
if (null == user) {
|
||||||
|
throw new IdsException(ErrorResponse.ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
user.setEmail(null);
|
||||||
|
user.setPhone_number(null);
|
||||||
|
IdsResponse<String, Object> idsResponse = new IdsResponse<>();
|
||||||
|
idsResponse.putAll(JsonUtil.parseKv(JsonUtil.toJsonString(user)));
|
||||||
|
return idsResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* ids The service endpoint that needs to be provided externally
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
package com.fujieid.jap.ids.endpoint;
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class IdsException extends RuntimeException {
|
||||||
|
|
||||||
|
private String error;
|
||||||
|
private String errorDescription;
|
||||||
|
|
||||||
|
public IdsException(String message) {
|
||||||
|
super(message);
|
||||||
|
this.errorDescription = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsException(String error, String errorDescription) {
|
||||||
|
super(error + ": " + errorDescription);
|
||||||
|
this.error = error;
|
||||||
|
this.errorDescription = errorDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsException(ErrorResponse errorResponse) {
|
||||||
|
this.error = errorResponse.getError();
|
||||||
|
this.errorDescription = errorResponse.getErrorDescription();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsException setError(String error) {
|
||||||
|
this.error = error;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorDescription() {
|
||||||
|
return errorDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsException setErrorDescription(String errorDescription) {
|
||||||
|
this.errorDescription = errorDescription;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class IdsTokenException extends IdsException {
|
||||||
|
|
||||||
|
public IdsTokenException(ErrorResponse codeEnum) {
|
||||||
|
super(codeEnum.getError(), codeEnum.getErrorDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsTokenException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class InvalidClientException extends IdsException {
|
||||||
|
|
||||||
|
public InvalidClientException(ErrorResponse codeEnum) {
|
||||||
|
super(codeEnum.getError(), codeEnum.getErrorDescription());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class InvalidCodeException extends IdsException {
|
||||||
|
|
||||||
|
public InvalidCodeException(ErrorResponse codeEnum) {
|
||||||
|
super(codeEnum.getError(), codeEnum.getErrorDescription());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class InvalidGrantException extends IdsException {
|
||||||
|
|
||||||
|
public InvalidGrantException(ErrorResponse codeEnum) {
|
||||||
|
super(codeEnum.getError(), codeEnum.getErrorDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidGrantException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class InvalidJwksException extends IdsException {
|
||||||
|
|
||||||
|
public InvalidJwksException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidJwksException(ErrorResponse errorResponse) {
|
||||||
|
super(errorResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidJwksException(String error, String errorDescription) {
|
||||||
|
super(error, errorDescription);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class InvalidRedirectUriException extends IdsException {
|
||||||
|
|
||||||
|
public InvalidRedirectUriException(ErrorResponse codeEnum) {
|
||||||
|
super(codeEnum.getError(), codeEnum.getErrorDescription());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class InvalidRequestException extends IdsException {
|
||||||
|
|
||||||
|
public InvalidRequestException(ErrorResponse codeEnum) {
|
||||||
|
super(codeEnum.getError(), codeEnum.getErrorDescription());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class InvalidScopeException extends IdsException {
|
||||||
|
|
||||||
|
public InvalidScopeException(ErrorResponse codeEnum) {
|
||||||
|
super(codeEnum.getError(), codeEnum.getErrorDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidScopeException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class InvalidTokenException extends IdsException {
|
||||||
|
|
||||||
|
public InvalidTokenException(ErrorResponse codeEnum) {
|
||||||
|
super(codeEnum.getError(), codeEnum.getErrorDescription());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class UnsupportedGrantTypeException extends IdsException {
|
||||||
|
|
||||||
|
public UnsupportedGrantTypeException(ErrorResponse codeEnum) {
|
||||||
|
super(codeEnum.getError(), codeEnum.getErrorDescription());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.exception;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class UnsupportedResponseTypeException extends IdsException {
|
||||||
|
|
||||||
|
public UnsupportedResponseTypeException(ErrorResponse codeEnum) {
|
||||||
|
super(codeEnum.getError(), codeEnum.getErrorDescription());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* ids exceptions
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
package com.fujieid.jap.ids.exception;
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.filter;
|
||||||
|
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import cn.hutool.log.LogFactory;
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.config.IdsConfig;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ids Filter
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class AbstractIdsFilter {
|
||||||
|
protected static final Log log = LogFactory.get();
|
||||||
|
protected final List<String> ignoreUrls = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether it is a servlet request that needs to be ignored
|
||||||
|
*
|
||||||
|
* @param request The current request to be intercepted
|
||||||
|
* @return boolean, the request does not need to be intercepted when true is returned
|
||||||
|
*/
|
||||||
|
protected boolean isIgnoredServletPath(HttpServletRequest request) {
|
||||||
|
String servletPath = request.getServletPath();
|
||||||
|
if (ignoreUrls.contains(servletPath)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (String ignoreUrl : ignoreUrls) {
|
||||||
|
if (ignoreUrl.contains("**")) {
|
||||||
|
String[] urls = ignoreUrl.split("/*/*");
|
||||||
|
if (urls.length == 1) {
|
||||||
|
if (servletPath.startsWith(urls[0])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (urls.length > 1) {
|
||||||
|
if (servletPath.startsWith(urls[0]) && servletPath.endsWith(urls[urls.length - 1])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the url of the filter to be released
|
||||||
|
*
|
||||||
|
* @param ignoreUrl URLs that do not need to be intercepted
|
||||||
|
*/
|
||||||
|
protected void initIgnoreUrls(String ignoreUrl) {
|
||||||
|
if (null != ignoreUrl) {
|
||||||
|
String[] ignoreUrls = ignoreUrl.split(",");
|
||||||
|
this.ignoreUrls.addAll(Arrays.asList(ignoreUrls));
|
||||||
|
} else {
|
||||||
|
// Fault-tolerant processing
|
||||||
|
IdsConfig config = JapIds.getIdsConfig();
|
||||||
|
String issuer = config.getIssuer();
|
||||||
|
String authorizeUrl = config.getAuthorizeUrl();
|
||||||
|
String loginUrl = config.getLoginUrl();
|
||||||
|
String errorUrl = config.getErrorUrl();
|
||||||
|
String confirmUrl = config.getConfirmUrl();
|
||||||
|
String tokenUrl = config.getTokenUrl();
|
||||||
|
String registrationUrl = config.getRegistrationUrl();
|
||||||
|
String jwksUrl = config.getJwksUrl();
|
||||||
|
String discoveryUrl = config.getDiscoveryUrl();
|
||||||
|
String[] urls = {authorizeUrl, loginUrl, errorUrl, confirmUrl, tokenUrl, registrationUrl, jwksUrl, discoveryUrl};
|
||||||
|
for (String url : urls) {
|
||||||
|
if (StringUtil.isNotEmpty(url) && url.startsWith(issuer)) {
|
||||||
|
this.ignoreUrls.add(url.substring(issuer.length()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.ignoreUrls.add("/favicon.ico");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.filter;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.util.TokenUtil;
|
||||||
|
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* access token filter to verify the validity of the token
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsAccessTokenFilter extends AbstractIdsFilter implements Filter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||||
|
|
||||||
|
boolean ignored = this.isIgnoredServletPath(request);
|
||||||
|
if (ignored) {
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.debug("{} - {}", request.getMethod(), request.getRequestURI());
|
||||||
|
String accessToken = TokenUtil.getAccessToken(request);
|
||||||
|
TokenUtil.validateAccessToken(accessToken);
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
Filter.super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
Filter.super.init(filterConfig);
|
||||||
|
String ignoreUrl = filterConfig.getInitParameter("ignoreUrl");
|
||||||
|
this.initIgnoreUrls(ignoreUrl);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.filter;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.exception.IdsException;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User status filter to verify the user's login status
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsUserStatusFilter extends AbstractIdsFilter implements Filter {
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||||
|
|
||||||
|
boolean ignored = this.isIgnoredServletPath(request);
|
||||||
|
if (ignored) {
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (JapIds.isAuthenticated(request)) {
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new IdsException(ErrorResponse.INVALID_USER_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
Filter.super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
Filter.super.init(filterConfig);
|
||||||
|
String ignoreUrl = filterConfig.getInitParameter("ignoreUrl");
|
||||||
|
this.initIgnoreUrls(ignoreUrl);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* ids filter, including access token filter and user status filter
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
package com.fujieid.jap.ids.filter;
|
139
jap-ids/src/main/java/com/fujieid/jap/ids/model/AccessToken.java
Normal file
139
jap-ids/src/main/java/com/fujieid/jap/ids/model/AccessToken.java
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* access token
|
||||||
|
*
|
||||||
|
* @author generate by HouTu Generator
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class AccessToken implements Serializable {
|
||||||
|
private String accessToken;
|
||||||
|
private String refreshToken;
|
||||||
|
private String userId;
|
||||||
|
private String userName;
|
||||||
|
private String grantType;
|
||||||
|
private String scope;
|
||||||
|
private String clientId;
|
||||||
|
private Long accessTokenExpiresIn;
|
||||||
|
private Long refreshTokenExpiresIn;
|
||||||
|
private LocalDateTime accessTokenExpiration;
|
||||||
|
private LocalDateTime refreshTokenExpiration;
|
||||||
|
|
||||||
|
public String getAccessToken() {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setAccessToken(String accessToken) {
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRefreshToken() {
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setRefreshToken(String refreshToken) {
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setUserId(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setUserName(String userName) {
|
||||||
|
this.userName = userName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGrantType() {
|
||||||
|
return grantType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setGrantType(String grantType) {
|
||||||
|
this.grantType = grantType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getScope() {
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setScope(String scope) {
|
||||||
|
this.scope = scope;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAccessTokenExpiresIn() {
|
||||||
|
return accessTokenExpiresIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setAccessTokenExpiresIn(Long accessTokenExpiresIn) {
|
||||||
|
this.accessTokenExpiresIn = accessTokenExpiresIn;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getRefreshTokenExpiresIn() {
|
||||||
|
return refreshTokenExpiresIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setRefreshTokenExpiresIn(Long refreshTokenExpiresIn) {
|
||||||
|
this.refreshTokenExpiresIn = refreshTokenExpiresIn;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getAccessTokenExpiration() {
|
||||||
|
return accessTokenExpiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setAccessTokenExpiration(LocalDateTime accessTokenExpiration) {
|
||||||
|
this.accessTokenExpiration = accessTokenExpiration;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getRefreshTokenExpiration() {
|
||||||
|
return refreshTokenExpiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessToken setRefreshTokenExpiration(LocalDateTime refreshTokenExpiration) {
|
||||||
|
this.refreshTokenExpiration = refreshTokenExpiration;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorization code
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class AuthCode implements Serializable {
|
||||||
|
private String scope;
|
||||||
|
private UserInfo user;
|
||||||
|
private String nonce;
|
||||||
|
private String codeChallengeMethod;
|
||||||
|
private String codeChallenge;
|
||||||
|
|
||||||
|
public String getScope() {
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthCode setScope(String scope) {
|
||||||
|
this.scope = scope;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthCode setUser(UserInfo user) {
|
||||||
|
this.user = user;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNonce() {
|
||||||
|
return nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthCode setNonce(String nonce) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeChallengeMethod() {
|
||||||
|
return codeChallengeMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthCode setCodeChallengeMethod(String codeChallengeMethod) {
|
||||||
|
this.codeChallengeMethod = codeChallengeMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeChallenge() {
|
||||||
|
return codeChallenge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthCode setCodeChallenge(String codeChallenge) {
|
||||||
|
this.codeChallenge = codeChallenge;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class ClientCertificate {
|
||||||
|
private String id;
|
||||||
|
private String secret;
|
||||||
|
|
||||||
|
public ClientCertificate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientCertificate(String id, String secret) {
|
||||||
|
this.id = id;
|
||||||
|
this.secret = secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientCertificate setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSecret() {
|
||||||
|
return secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientCertificate setSecret(String secret) {
|
||||||
|
this.secret = secret;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class ClientDetail implements Serializable {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用名
|
||||||
|
*/
|
||||||
|
private String appName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用ID
|
||||||
|
*/
|
||||||
|
private String clientId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用密钥
|
||||||
|
*/
|
||||||
|
private String clientSecret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义二级域名
|
||||||
|
*/
|
||||||
|
private String siteDomain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证成功后跳转的地址
|
||||||
|
*/
|
||||||
|
private String redirectUri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出成功后跳转的地址
|
||||||
|
*/
|
||||||
|
private String logoutRedirectUri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用图标
|
||||||
|
*/
|
||||||
|
private String logo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否可用
|
||||||
|
*/
|
||||||
|
private Boolean available;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限范围
|
||||||
|
*/
|
||||||
|
private String scopes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权类型
|
||||||
|
*/
|
||||||
|
private String grantTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回类型
|
||||||
|
*/
|
||||||
|
private String responseTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* code 授权码有效时间(秒)
|
||||||
|
*/
|
||||||
|
private Long codeExpiresIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id token有效时间(秒)
|
||||||
|
*/
|
||||||
|
private Long idTokenExpiresIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* access token有效时间(秒)
|
||||||
|
*/
|
||||||
|
private Long accessTokenExpiresIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* refresh token有效时间(秒)
|
||||||
|
*/
|
||||||
|
private Long refreshTokenExpiresIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附加信息
|
||||||
|
*/
|
||||||
|
private String additionalInformation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动批准(不显示确认页面)
|
||||||
|
*/
|
||||||
|
private Boolean autoApprove;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用 PKCE 增强协议
|
||||||
|
*/
|
||||||
|
private Boolean enablePkce;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PKCE 质询码的加密方式
|
||||||
|
*/
|
||||||
|
private String codeChallengeMethod;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAppName() {
|
||||||
|
return appName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setAppName(String appName) {
|
||||||
|
this.appName = appName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientSecret() {
|
||||||
|
return clientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setClientSecret(String clientSecret) {
|
||||||
|
this.clientSecret = clientSecret;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSiteDomain() {
|
||||||
|
return siteDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setSiteDomain(String siteDomain) {
|
||||||
|
this.siteDomain = siteDomain;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRedirectUri() {
|
||||||
|
return redirectUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setRedirectUri(String redirectUri) {
|
||||||
|
this.redirectUri = redirectUri;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLogoutRedirectUri() {
|
||||||
|
return logoutRedirectUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setLogoutRedirectUri(String logoutRedirectUri) {
|
||||||
|
this.logoutRedirectUri = logoutRedirectUri;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLogo() {
|
||||||
|
return logo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setLogo(String logo) {
|
||||||
|
this.logo = logo;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getAvailable() {
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setAvailable(Boolean available) {
|
||||||
|
this.available = available;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getScopes() {
|
||||||
|
return scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setScopes(String scopes) {
|
||||||
|
this.scopes = scopes;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGrantTypes() {
|
||||||
|
return grantTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setGrantTypes(String grantTypes) {
|
||||||
|
this.grantTypes = grantTypes;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResponseTypes() {
|
||||||
|
return responseTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setResponseTypes(String responseTypes) {
|
||||||
|
this.responseTypes = responseTypes;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCodeExpiresIn() {
|
||||||
|
return codeExpiresIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setCodeExpiresIn(Long codeExpiresIn) {
|
||||||
|
this.codeExpiresIn = codeExpiresIn;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getIdTokenExpiresIn() {
|
||||||
|
return idTokenExpiresIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setIdTokenExpiresIn(Long idTokenExpiresIn) {
|
||||||
|
this.idTokenExpiresIn = idTokenExpiresIn;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAccessTokenExpiresIn() {
|
||||||
|
return accessTokenExpiresIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setAccessTokenExpiresIn(Long accessTokenExpiresIn) {
|
||||||
|
this.accessTokenExpiresIn = accessTokenExpiresIn;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getRefreshTokenExpiresIn() {
|
||||||
|
return refreshTokenExpiresIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setRefreshTokenExpiresIn(Long refreshTokenExpiresIn) {
|
||||||
|
this.refreshTokenExpiresIn = refreshTokenExpiresIn;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAdditionalInformation() {
|
||||||
|
return additionalInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setAdditionalInformation(String additionalInformation) {
|
||||||
|
this.additionalInformation = additionalInformation;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getAutoApprove() {
|
||||||
|
return autoApprove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setAutoApprove(Boolean autoApprove) {
|
||||||
|
this.autoApprove = autoApprove;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getEnablePkce() {
|
||||||
|
return enablePkce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setEnablePkce(Boolean enablePkce) {
|
||||||
|
this.enablePkce = enablePkce;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeChallengeMethod() {
|
||||||
|
return codeChallengeMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientDetail setCodeChallengeMethod(String codeChallengeMethod) {
|
||||||
|
this.codeChallengeMethod = codeChallengeMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
120
jap-ids/src/main/java/com/fujieid/jap/ids/model/IdsConsts.java
Normal file
120
jap-ids/src/main/java/com/fujieid/jap/ids/model/IdsConsts.java
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ids constant
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public interface IdsConsts {
|
||||||
|
String SLASH = "/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default validity period of the authorization code is 10 minutes (600 seconds)
|
||||||
|
*/
|
||||||
|
long AUTHORIZATION_CODE_ACTIVITY_TIME = 600;
|
||||||
|
/**
|
||||||
|
* The default validity period of access token is 30 days (2592000 seconds)
|
||||||
|
*/
|
||||||
|
long ACCESS_TOKEN_ACTIVITY_TIME = 2592000;
|
||||||
|
/**
|
||||||
|
* The default validity period of refresh token is 365 days (31536000 seconds)
|
||||||
|
*/
|
||||||
|
long REFRESH_TOKEN_ACTIVITY_TIME = 31536000;
|
||||||
|
/**
|
||||||
|
* The default validity period of id token is 365 days (31536000 seconds)
|
||||||
|
*/
|
||||||
|
long ID_TOKEN_ACTIVITY_TIME = 31536000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token header name
|
||||||
|
*/
|
||||||
|
String AUTHORIZATION_HEADER_NAME = "Authorization";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token Type
|
||||||
|
*/
|
||||||
|
String TOKEN_TYPE_BEARER = "Bearer";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache key of oauth authorized user
|
||||||
|
*/
|
||||||
|
String IDS_OAUTH_CACHE_KEY = "JAPIDS:OAUTH2:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache key of oauth authorized user
|
||||||
|
*/
|
||||||
|
String OAUTH_USERINFO_CACHE_KEY = IDS_OAUTH_CACHE_KEY + "USERINFO";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache the key of access token
|
||||||
|
*/
|
||||||
|
String OAUTH_ACCESS_TOKEN_CACHE_KEY = IDS_OAUTH_CACHE_KEY + "ACCESS_TOKEN:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache the key of refresh token
|
||||||
|
*/
|
||||||
|
String OAUTH_REFRESH_TOKEN_CACHE_KEY = IDS_OAUTH_CACHE_KEY + "REFRESH_TOKEN:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache the key of the oauth code
|
||||||
|
*/
|
||||||
|
String OAUTH_CODE_CACHE_KEY = IDS_OAUTH_CACHE_KEY + "CODE:";
|
||||||
|
|
||||||
|
String CODE_CHALLENGE = "code_challenge";
|
||||||
|
String CODE_CHALLENGE_METHOD = "code_challenge_method";
|
||||||
|
String CODE_VERIFIER = "code_verifier";
|
||||||
|
String CLIENT_ID = "client_id";
|
||||||
|
String CLIENT_SECRET = "client_secret";
|
||||||
|
String SCOPE = "scope";
|
||||||
|
String REDIRECT_URI = "redirect_uri";
|
||||||
|
String STATE = "state";
|
||||||
|
String RESPONSE_TYPE = "response_type";
|
||||||
|
String GRANT_TYPE = "grant_type";
|
||||||
|
String TOKEN_TYPE = "token_type";
|
||||||
|
String ACCESS_TOKEN = "access_token";
|
||||||
|
String REFRESH_TOKEN = "refresh_token";
|
||||||
|
String ID_TOKEN = "id_token";
|
||||||
|
String EXPIRES_IN = "expires_in";
|
||||||
|
String UID = "uid";
|
||||||
|
String CODE = "code";
|
||||||
|
String RESPONSE_MODE = "response_mode";
|
||||||
|
String DISPLAY = "display";
|
||||||
|
String PROMPT = "prompt";
|
||||||
|
String MAX_AGE = "max_age";
|
||||||
|
String ID_TOKEN_HINT = "id_token_hint";
|
||||||
|
String AUTOAPPROVE = "autoapprove";
|
||||||
|
String USERNAME = "username";
|
||||||
|
String PASSWORD = "password";
|
||||||
|
/**
|
||||||
|
* {@code auth_time} - the time when the End-User authentication occurred
|
||||||
|
*/
|
||||||
|
String AUTH_TIME = "auth_time";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code nonce} - a {@code String} value used to associate a Client session with an ID Token,
|
||||||
|
* and to mitigate replay attacks.
|
||||||
|
*/
|
||||||
|
String NONCE = "nonce";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code acr} - the Authentication Context Class Reference
|
||||||
|
*/
|
||||||
|
String ACR = "acr";
|
||||||
|
}
|
@ -0,0 +1,329 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model;
|
||||||
|
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters of oauth request
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsRequestParam {
|
||||||
|
private String clientId;
|
||||||
|
private String clientSecret;
|
||||||
|
private String grantType;
|
||||||
|
private String code;
|
||||||
|
private String redirectUri;
|
||||||
|
private String scope;
|
||||||
|
private String state;
|
||||||
|
private String accessToken;
|
||||||
|
private String refreshToken;
|
||||||
|
private String responseType;
|
||||||
|
private String uid;
|
||||||
|
private String autoapprove;
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private String codeVerifier;
|
||||||
|
private String codeChallengeMethod;
|
||||||
|
private String codeChallenge;
|
||||||
|
|
||||||
|
/* The following are the parameters supported by the oidc protocol, referenced from: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* optional, The nonce parameter value needs to include per-session state and be unguessable to attackers
|
||||||
|
*/
|
||||||
|
private String nonce;
|
||||||
|
/**
|
||||||
|
* Optional. The newly defined parameter of oidc (oauth 2.0 form post response mode) is used to specify how the authorization endpoint returns data.
|
||||||
|
*/
|
||||||
|
private String responseMode;
|
||||||
|
/**
|
||||||
|
* OPTIONAL. ASCII string value that specifies how the Authorization Server displays the authentication and consent user interface pages to the End-User. The defined values are:
|
||||||
|
* <p>
|
||||||
|
* <strong>page</strong> - The Authorization Server SHOULD display the authentication and consent UI consistent with a full User Agent page view.
|
||||||
|
* If the display parameter is not specified, this is the default display mode.
|
||||||
|
* <p>
|
||||||
|
* <strong>popup</strong> - The Authorization Server SHOULD display the authentication and consent UI consistent with a popup User Agent window.
|
||||||
|
* The popup User Agent window should be of an appropriate size for a login-focused dialog and should not obscure the entire window that it is popping up over.
|
||||||
|
* <p>
|
||||||
|
* <strong>touch</strong> - The Authorization Server SHOULD display the authentication and consent UI consistent with a device that leverages a touch interface.
|
||||||
|
* <p>
|
||||||
|
* <strong>wap</strong> - The Authorization Server SHOULD display the authentication and consent UI consistent with a "feature phone" type display.
|
||||||
|
*/
|
||||||
|
private String display;
|
||||||
|
/**
|
||||||
|
* OPTIONAL. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for reauthentication and consent. The defined values are:
|
||||||
|
* <p>
|
||||||
|
* <strong>none</strong> - The Authorization Server MUST NOT display any authentication or consent user interface pages.
|
||||||
|
* An error is returned if an End-User is not already authenticated or the Client does not have pre-configured
|
||||||
|
* consent for the requested Claims or does not fulfill other conditions for processing the request.
|
||||||
|
* The error code will typically be login_required, interaction_required, or another code defined in Section 3.1.2.6.
|
||||||
|
* This can be used as a method to check for existing authentication and/or consent.
|
||||||
|
* <p>
|
||||||
|
* <strong>login</strong> - The Authorization Server SHOULD prompt the End-User for reauthentication.
|
||||||
|
* If it cannot reauthenticate the End-User, it MUST return an error, typically login_required.
|
||||||
|
* <p>
|
||||||
|
* <strong>consent</strong> - The Authorization Server SHOULD prompt the End-User for consent before returning information to the Client.
|
||||||
|
* If it cannot obtain consent, it MUST return an error, typically consent_required.
|
||||||
|
* <p>
|
||||||
|
* <strong>select_account</strong> - The Authorization Server SHOULD prompt the End-User to select a user account.
|
||||||
|
* This enables an End-User who has multiple accounts at the Authorization Server to select amongst
|
||||||
|
* the multiple accounts that they might have current sessions for.
|
||||||
|
* If it cannot obtain an account selection choice made by the End-User,
|
||||||
|
* it MUST return an error, typically account_selection_required.
|
||||||
|
*/
|
||||||
|
private String prompt;
|
||||||
|
/**
|
||||||
|
* Optional. Represents the valid time of the eu authentication information,
|
||||||
|
* corresponding to the claim of auth time in the id token. For example,
|
||||||
|
* if the setting is 20 minutes, if the time is exceeded, you need to guide eu to re-authenticate.
|
||||||
|
*/
|
||||||
|
private String authTime;
|
||||||
|
/**
|
||||||
|
* Optional. For the previously issued id token, if the id token is verified and valid, it needs to return a normal response;
|
||||||
|
* if there is an error, it returns a corresponding error prompt.
|
||||||
|
*/
|
||||||
|
private String idTokenHint;
|
||||||
|
/**
|
||||||
|
* Optional. Requested Authentication Context Class Reference values.
|
||||||
|
* Space-separated string that specifies the acr values that the Authorization Server is being requested to use for processing this Authentication Request,
|
||||||
|
* with the values appearing in order of preference
|
||||||
|
*/
|
||||||
|
private String acr;
|
||||||
|
|
||||||
|
public boolean isEnablePkce() {
|
||||||
|
return !StringUtil.isEmpty(this.getCodeVerifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setClientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientSecret() {
|
||||||
|
return clientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setClientSecret(String clientSecret) {
|
||||||
|
this.clientSecret = clientSecret;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGrantType() {
|
||||||
|
return grantType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setGrantType(String grantType) {
|
||||||
|
this.grantType = grantType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setCode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRedirectUri() {
|
||||||
|
return redirectUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setRedirectUri(String redirectUri) {
|
||||||
|
this.redirectUri = redirectUri;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getScope() {
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setScope(String scope) {
|
||||||
|
this.scope = scope;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setState(String state) {
|
||||||
|
this.state = state;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccessToken() {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setAccessToken(String accessToken) {
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRefreshToken() {
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setRefreshToken(String refreshToken) {
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResponseType() {
|
||||||
|
return responseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setResponseType(String responseType) {
|
||||||
|
this.responseType = responseType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUid() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setUid(String uid) {
|
||||||
|
this.uid = uid;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNonce() {
|
||||||
|
return nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setNonce(String nonce) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResponseMode() {
|
||||||
|
return responseMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setResponseMode(String responseMode) {
|
||||||
|
this.responseMode = responseMode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplay() {
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setDisplay(String display) {
|
||||||
|
this.display = display;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrompt() {
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setPrompt(String prompt) {
|
||||||
|
this.prompt = prompt;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthTime() {
|
||||||
|
return authTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setAuthTime(String authTime) {
|
||||||
|
this.authTime = authTime;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIdTokenHint() {
|
||||||
|
return idTokenHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setIdTokenHint(String idTokenHint) {
|
||||||
|
this.idTokenHint = idTokenHint;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAcr() {
|
||||||
|
return acr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setAcr(String acr) {
|
||||||
|
this.acr = acr;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAutoapprove() {
|
||||||
|
return autoapprove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setAutoapprove(String autoapprove) {
|
||||||
|
this.autoapprove = autoapprove;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeVerifier() {
|
||||||
|
return codeVerifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setCodeVerifier(String codeVerifier) {
|
||||||
|
this.codeVerifier = codeVerifier;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeChallengeMethod() {
|
||||||
|
return codeChallengeMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setCodeChallengeMethod(String codeChallengeMethod) {
|
||||||
|
this.codeChallengeMethod = codeChallengeMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeChallenge() {
|
||||||
|
return codeChallenge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsRequestParam setCodeChallenge(String codeChallenge) {
|
||||||
|
this.codeChallenge = codeChallenge;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
102
jap-ids/src/main/java/com/fujieid/jap/ids/model/IdsResponse.java
Normal file
102
jap-ids/src/main/java/com/fujieid/jap/ids/model/IdsResponse.java
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsResponse<K, V> extends HashMap<String, Object> {
|
||||||
|
private final String error = "error";
|
||||||
|
private final String error_description = "error_description";
|
||||||
|
private final String error_uri = "error_uri";
|
||||||
|
private final String state = "state";
|
||||||
|
private final String data = "data";
|
||||||
|
|
||||||
|
public IdsResponse<K, V> error(ErrorResponse errorCode) {
|
||||||
|
return this.error(errorCode.getError())
|
||||||
|
.errorDescription(errorCode.getErrorDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsResponse<K, V> error(String errorCode) {
|
||||||
|
this.put(this.error, errorCode);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsResponse<K, V> errorDescription(String errorDescription) {
|
||||||
|
this.put(this.error_description, errorDescription);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsResponse<K, V> errorUri(String errorUri) {
|
||||||
|
this.put(this.error_uri, errorUri);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsResponse<K, V> state(String state) {
|
||||||
|
this.put(this.state, state);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsResponse<K, V> data(Object data) {
|
||||||
|
this.put(this.error, "");
|
||||||
|
this.put(this.error_description, "");
|
||||||
|
this.put(this.data, data);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return StringUtil.isEmpty(this.getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsResponse<K, V> add(String key, Object value) {
|
||||||
|
this.put(key, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsResponse<K, V> addAll(Map<String, Object> map) {
|
||||||
|
this.putAll(map);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getError() {
|
||||||
|
return ObjectUtil.isEmpty(this.get(error)) ? null : String.valueOf(this.get(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorDescription() {
|
||||||
|
return ObjectUtil.isEmpty(this.get(error_description)) ? null : String.valueOf(this.get(error_description));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorUri() {
|
||||||
|
return ObjectUtil.isEmpty(this.get(error_uri)) ? null : String.valueOf(this.get(error_uri));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getState() {
|
||||||
|
return ObjectUtil.isEmpty(this.get(state)) ? null : String.valueOf(this.get(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getData() {
|
||||||
|
return this.get(data);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsScope implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scope code, such as: basic, super
|
||||||
|
*/
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scope description
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsScope setCode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdsScope setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class OidcDiscoveryDto implements Serializable {
|
||||||
|
|
||||||
|
private String issuer;
|
||||||
|
private String authorization_endpoint;
|
||||||
|
private String token_endpoint;
|
||||||
|
private String userinfo_endpoint;
|
||||||
|
private String registration_endpoint;
|
||||||
|
private String end_session_endpoint;
|
||||||
|
private String check_session_iframe;
|
||||||
|
private String jwks_uri;
|
||||||
|
private List<String> grant_types_supported;
|
||||||
|
private List<String> response_modes_supported;
|
||||||
|
private List<String> response_types_supported;
|
||||||
|
private List<String> scopes_supported;
|
||||||
|
private List<String> token_endpoint_auth_methods_supported;
|
||||||
|
private List<String> request_object_signing_alg_values_supported;
|
||||||
|
private List<String> userinfo_signing_alg_values_supported;
|
||||||
|
private boolean request_parameter_supported;
|
||||||
|
private boolean request_uri_parameter_supported;
|
||||||
|
private boolean require_request_uri_registration;
|
||||||
|
private boolean claims_parameter_supported;
|
||||||
|
private List<String> id_token_signing_alg_values_supported;
|
||||||
|
private List<String> subject_types_supported;
|
||||||
|
private List<String> claims_supported;
|
||||||
|
|
||||||
|
public String getIssuer() {
|
||||||
|
return issuer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setIssuer(String issuer) {
|
||||||
|
this.issuer = issuer;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthorization_endpoint() {
|
||||||
|
return authorization_endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setAuthorization_endpoint(String authorization_endpoint) {
|
||||||
|
this.authorization_endpoint = authorization_endpoint;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken_endpoint() {
|
||||||
|
return token_endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setToken_endpoint(String token_endpoint) {
|
||||||
|
this.token_endpoint = token_endpoint;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserinfo_endpoint() {
|
||||||
|
return userinfo_endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setUserinfo_endpoint(String userinfo_endpoint) {
|
||||||
|
this.userinfo_endpoint = userinfo_endpoint;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegistration_endpoint() {
|
||||||
|
return registration_endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setRegistration_endpoint(String registration_endpoint) {
|
||||||
|
this.registration_endpoint = registration_endpoint;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEnd_session_endpoint() {
|
||||||
|
return end_session_endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setEnd_session_endpoint(String end_session_endpoint) {
|
||||||
|
this.end_session_endpoint = end_session_endpoint;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCheck_session_iframe() {
|
||||||
|
return check_session_iframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setCheck_session_iframe(String check_session_iframe) {
|
||||||
|
this.check_session_iframe = check_session_iframe;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJwks_uri() {
|
||||||
|
return jwks_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setJwks_uri(String jwks_uri) {
|
||||||
|
this.jwks_uri = jwks_uri;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getGrant_types_supported() {
|
||||||
|
return grant_types_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setGrant_types_supported(List<String> grant_types_supported) {
|
||||||
|
this.grant_types_supported = grant_types_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getResponse_modes_supported() {
|
||||||
|
return response_modes_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setResponse_modes_supported(List<String> response_modes_supported) {
|
||||||
|
this.response_modes_supported = response_modes_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getResponse_types_supported() {
|
||||||
|
return response_types_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setResponse_types_supported(List<String> response_types_supported) {
|
||||||
|
this.response_types_supported = response_types_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getScopes_supported() {
|
||||||
|
return scopes_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setScopes_supported(List<String> scopes_supported) {
|
||||||
|
this.scopes_supported = scopes_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getToken_endpoint_auth_methods_supported() {
|
||||||
|
return token_endpoint_auth_methods_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setToken_endpoint_auth_methods_supported(List<String> token_endpoint_auth_methods_supported) {
|
||||||
|
this.token_endpoint_auth_methods_supported = token_endpoint_auth_methods_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getRequest_object_signing_alg_values_supported() {
|
||||||
|
return request_object_signing_alg_values_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setRequest_object_signing_alg_values_supported(List<String> request_object_signing_alg_values_supported) {
|
||||||
|
this.request_object_signing_alg_values_supported = request_object_signing_alg_values_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getUserinfo_signing_alg_values_supported() {
|
||||||
|
return userinfo_signing_alg_values_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setUserinfo_signing_alg_values_supported(List<String> userinfo_signing_alg_values_supported) {
|
||||||
|
this.userinfo_signing_alg_values_supported = userinfo_signing_alg_values_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRequest_parameter_supported() {
|
||||||
|
return request_parameter_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setRequest_parameter_supported(boolean request_parameter_supported) {
|
||||||
|
this.request_parameter_supported = request_parameter_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRequest_uri_parameter_supported() {
|
||||||
|
return request_uri_parameter_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setRequest_uri_parameter_supported(boolean request_uri_parameter_supported) {
|
||||||
|
this.request_uri_parameter_supported = request_uri_parameter_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRequire_request_uri_registration() {
|
||||||
|
return require_request_uri_registration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setRequire_request_uri_registration(boolean require_request_uri_registration) {
|
||||||
|
this.require_request_uri_registration = require_request_uri_registration;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClaims_parameter_supported() {
|
||||||
|
return claims_parameter_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setClaims_parameter_supported(boolean claims_parameter_supported) {
|
||||||
|
this.claims_parameter_supported = claims_parameter_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getId_token_signing_alg_values_supported() {
|
||||||
|
return id_token_signing_alg_values_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setId_token_signing_alg_values_supported(List<String> id_token_signing_alg_values_supported) {
|
||||||
|
this.id_token_signing_alg_values_supported = id_token_signing_alg_values_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getSubject_types_supported() {
|
||||||
|
return subject_types_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setSubject_types_supported(List<String> subject_types_supported) {
|
||||||
|
this.subject_types_supported = subject_types_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getClaims_supported() {
|
||||||
|
return claims_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OidcDiscoveryDto setClaims_supported(List<String> claims_supported) {
|
||||||
|
this.claims_supported = claims_supported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
346
jap-ids/src/main/java/com/fujieid/jap/ids/model/UserInfo.java
Normal file
346
jap-ids/src/main/java/com/fujieid/jap/ids/model/UserInfo.java
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model;
|
||||||
|
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User info
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims" target="_blank">Standard Claims</a>
|
||||||
|
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse" target="_blank">UserInfo Response</a>
|
||||||
|
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html#IDToken" target="_blank">ID Token</a>
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class UserInfo implements Serializable {
|
||||||
|
/**
|
||||||
|
* string Subject - Identifier for the End-User at the Issuer.
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
/**
|
||||||
|
* string Subject - Identifier for the End-User at the Issuer.
|
||||||
|
*/
|
||||||
|
private String sub;
|
||||||
|
/**
|
||||||
|
* string End-User's full name in displayable form including all name parts, possibly including titles and suffixes,
|
||||||
|
* ordered according to the End-User's locale and preferences.
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
/**
|
||||||
|
* string End-User's full name in displayable form including all name parts, possibly including titles and suffixes,
|
||||||
|
* ordered according to the End-User's locale and preferences.
|
||||||
|
*/
|
||||||
|
private String username;
|
||||||
|
/**
|
||||||
|
* string Given name(s) or first name(s) of the End-User. Note that in some cultures, people can have multiple given names;
|
||||||
|
* all can be present, with the names being separated by space characters.
|
||||||
|
*/
|
||||||
|
private String given_name;
|
||||||
|
/**
|
||||||
|
* string Surname(s) or last name(s) of the End-User. Note that in some cultures, people can have multiple family names or no family name;
|
||||||
|
* all can be present, with the names being separated by space characters.
|
||||||
|
*/
|
||||||
|
private String family_name;
|
||||||
|
/**
|
||||||
|
* string Middle name(s) of the End-User. Note that in some cultures, people can have multiple middle names;
|
||||||
|
* all can be present, with the names being separated by space characters. Also note that in some cultures, middle names are not used.
|
||||||
|
*/
|
||||||
|
private String middle_name;
|
||||||
|
/**
|
||||||
|
* string Casual name of the End-User that may or may not be the same as the given_name. For instance,
|
||||||
|
* a nickname value of Mike might be returned alongside a given_name value of Michael.
|
||||||
|
*/
|
||||||
|
private String nickname;
|
||||||
|
/**
|
||||||
|
* string Shorthand name by which the End-User wishes to be referred to at the RP, such as janedoe or j.doe.
|
||||||
|
* This value MAY be any valid JSON string including special characters such as @, /, or whitespace.
|
||||||
|
* The RP MUST NOT rely upon this value being unique, as discussed in Section 5.7.
|
||||||
|
*/
|
||||||
|
private String preferred_username;
|
||||||
|
/**
|
||||||
|
* string URL of the End-User's profile page. The contents of this Web page SHOULD be about the End-User.
|
||||||
|
*/
|
||||||
|
private String profile;
|
||||||
|
/**
|
||||||
|
* string URL of the End-User's profile picture. This URL MUST refer to an image file (for example, a PNG, JPEG,
|
||||||
|
* or GIF image file), rather than to a Web page containing an image.
|
||||||
|
* Note that this URL SHOULD specifically reference a profile photo of the End-User suitable for displaying when describing the End-User,
|
||||||
|
* rather than an arbitrary photo taken by the End-User.
|
||||||
|
*/
|
||||||
|
private String picture;
|
||||||
|
/**
|
||||||
|
* string URL of the End-User's Web page or blog. This Web page SHOULD contain information published by the End-User
|
||||||
|
* or an organization that the End-User is affiliated with.
|
||||||
|
*/
|
||||||
|
private String website;
|
||||||
|
/**
|
||||||
|
* string End-User's preferred e-mail address. Its value MUST conform to the RFC 5322 [RFC5322] addr-spec syntax.
|
||||||
|
* The RP MUST NOT rely upon this value being unique, as discussed in Section 5.7.
|
||||||
|
*/
|
||||||
|
private String email;
|
||||||
|
/**
|
||||||
|
* boolean True if the End-User's e-mail address has been verified; otherwise false. When this Claim Value is true,
|
||||||
|
* this means that the OP took affirmative steps to ensure that this e-mail address was controlled by the End-User at the time the verification was performed.
|
||||||
|
* The means by which an e-mail address is verified is context-specific, and dependent upon the trust framework or contractual agreements within which the parties are operating.
|
||||||
|
*/
|
||||||
|
private String email_verified;
|
||||||
|
/**
|
||||||
|
* string End-User's gender. Values defined by this specification are female and male.
|
||||||
|
* Other values MAY be used when neither of the defined values are applicable.
|
||||||
|
*/
|
||||||
|
private String gender;
|
||||||
|
/**
|
||||||
|
* string End-User's birthday, represented as an ISO 8601:2004 [ISO8601‑2004] YYYY-MM-DD format. The year MAY be 0000,
|
||||||
|
* indicating that it is omitted. To represent only the year, YYYY format is allowed.
|
||||||
|
* Note that depending on the underlying platform's date related function, providing just year can result in varying month and day,
|
||||||
|
* so the implementers need to take this factor into account to correctly process the dates.
|
||||||
|
*/
|
||||||
|
private String birthdate;
|
||||||
|
/**
|
||||||
|
* string String from zoneinfo [zoneinfo] time zone database representing the End-User's time zone. For example,
|
||||||
|
* Europe/Paris or America/Los_Angeles.
|
||||||
|
*/
|
||||||
|
private String zoneinfo;
|
||||||
|
/**
|
||||||
|
* string End-User's locale, represented as a BCP47 [RFC5646] language tag.
|
||||||
|
* This is typically an ISO 639-1 Alpha-2 [ISO639‑1] language code in lowercase and an ISO 3166-1 Alpha-2 [ISO3166‑1] country code in uppercase,
|
||||||
|
* separated by a dash. For example, en-US or fr-CA. As a compatibility note, some implementations have used an underscore as the separator rather than a dash,
|
||||||
|
* for example, en_US; Relying Parties MAY choose to accept this locale syntax as well.
|
||||||
|
*/
|
||||||
|
private String locale;
|
||||||
|
/**
|
||||||
|
* string End-User's preferred telephone number. E.164 [E.164] is RECOMMENDED as the format of this Claim,
|
||||||
|
* for example, +1 (425) 555-1212 or +56 (2) 687 2400. If the phone number contains an extension,
|
||||||
|
* it is RECOMMENDED that the extension be represented using the RFC 3966 [RFC3966] extension syntax,
|
||||||
|
* for example, +1 (604) 555-1234;ext=5678.
|
||||||
|
*/
|
||||||
|
private String phone_number;
|
||||||
|
/**
|
||||||
|
* boolean True if the End-User's phone number has been verified; otherwise false. When this Claim Value is true,
|
||||||
|
* this means that the OP took affirmative steps to ensure that this phone number was controlled by the End-User at the time the verification was performed.
|
||||||
|
* The means by which a phone number is verified is context-specific, and dependent upon the trust framework or contractual agreements within which the parties are operating.
|
||||||
|
* When true, the phone_number Claim MUST be in E.164 format and any extensions MUST be represented in RFC 3966 format.
|
||||||
|
*/
|
||||||
|
private String phone_number_verified;
|
||||||
|
/**
|
||||||
|
* JSON object End-User's preferred postal address. The value of the address member is a JSON [RFC4627] structure containing some or all of the members defined in Section 5.1.1.
|
||||||
|
*/
|
||||||
|
private Map<String, String> address;
|
||||||
|
private String updated_at;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSub() {
|
||||||
|
return StringUtil.isEmpty(sub) ? getId() : sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setSub(String sub) {
|
||||||
|
this.sub = sub;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGiven_name() {
|
||||||
|
return given_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setGiven_name(String given_name) {
|
||||||
|
this.given_name = given_name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFamily_name() {
|
||||||
|
return family_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setFamily_name(String family_name) {
|
||||||
|
this.family_name = family_name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMiddle_name() {
|
||||||
|
return middle_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setMiddle_name(String middle_name) {
|
||||||
|
this.middle_name = middle_name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNickname() {
|
||||||
|
return nickname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setNickname(String nickname) {
|
||||||
|
this.nickname = nickname;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPreferred_username() {
|
||||||
|
return preferred_username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setPreferred_username(String preferred_username) {
|
||||||
|
this.preferred_username = preferred_username;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProfile() {
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setProfile(String profile) {
|
||||||
|
this.profile = profile;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPicture() {
|
||||||
|
return picture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setPicture(String picture) {
|
||||||
|
this.picture = picture;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWebsite() {
|
||||||
|
return website;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setWebsite(String website) {
|
||||||
|
this.website = website;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail_verified() {
|
||||||
|
return email_verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setEmail_verified(String email_verified) {
|
||||||
|
this.email_verified = email_verified;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGender() {
|
||||||
|
return gender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setGender(String gender) {
|
||||||
|
this.gender = gender;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBirthdate() {
|
||||||
|
return birthdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setBirthdate(String birthdate) {
|
||||||
|
this.birthdate = birthdate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZoneinfo() {
|
||||||
|
return zoneinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setZoneinfo(String zoneinfo) {
|
||||||
|
this.zoneinfo = zoneinfo;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocale() {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setLocale(String locale) {
|
||||||
|
this.locale = locale;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhone_number() {
|
||||||
|
return phone_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setPhone_number(String phone_number) {
|
||||||
|
this.phone_number = phone_number;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhone_number_verified() {
|
||||||
|
return phone_number_verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setPhone_number_verified(String phone_number_verified) {
|
||||||
|
this.phone_number_verified = phone_number_verified;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setAddress(Map<String, String> address) {
|
||||||
|
this.address = address;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUpdated_at() {
|
||||||
|
return updated_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserInfo setUpdated_at(String updated_at) {
|
||||||
|
this.updated_at = updated_at;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model.enums;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The client secret authentication method supports the following four situations:
|
||||||
|
* <p>
|
||||||
|
* 1. Post parameter: {@link ClientSecretAuthMethod#CLIENT_SECRET_POST}
|
||||||
|
* <p>
|
||||||
|
* 2. The basic format string in the request header:{@link ClientSecretAuthMethod#CLIENT_SECRET_BASIC}
|
||||||
|
* <p>
|
||||||
|
* 3. url: {@link ClientSecretAuthMethod#NONE}
|
||||||
|
* <p>
|
||||||
|
* 4. All of the above support: {@link ClientSecretAuthMethod#ALL}
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public enum ClientSecretAuthMethod {
|
||||||
|
/**
|
||||||
|
* Post parameter
|
||||||
|
*/
|
||||||
|
CLIENT_SECRET_POST,
|
||||||
|
/**
|
||||||
|
* The basic format string in the request header
|
||||||
|
*/
|
||||||
|
CLIENT_SECRET_BASIC,
|
||||||
|
/**
|
||||||
|
* url
|
||||||
|
*/
|
||||||
|
NONE,
|
||||||
|
/**
|
||||||
|
* All of the above support
|
||||||
|
*/
|
||||||
|
ALL;
|
||||||
|
|
||||||
|
public static List<String> getAllMethods() {
|
||||||
|
return Arrays.stream(ClientSecretAuthMethod.values())
|
||||||
|
.filter((method) -> method != ALL)
|
||||||
|
.map((method) -> method.name().toLowerCase())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMethod() {
|
||||||
|
return this.name().toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model.enums;
|
||||||
|
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorization error code
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.1.2.1" target="_blank">https://tools.ietf.org/html/rfc6749#section-4.1.2.1</a>
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-5.2" target="_blank">https://tools.ietf.org/html/rfc6749#section-5.2</a>
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public enum ErrorResponse {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorization error code
|
||||||
|
*/
|
||||||
|
INVALID_REQUEST("invalid_request", "Request parameters are missing or not supported or incorrect."),
|
||||||
|
INVALID_CLIENT("invalid_client", "The requested client id or client secret parameter is invalid."),
|
||||||
|
INVALID_GRANT("invalid_grant", "Invalid grant, request parameters are incorrect or expired."),
|
||||||
|
INVALID_CODE("invalid_code", "The authorization code is invalid or expired."),
|
||||||
|
INVALID_USER_CERTIFICATE("invalid_user_certificate", "Invalid user credentials."),
|
||||||
|
INVALID_USER_STATUS("invalid_user_status", "Invalid user status, the user may have logged out."),
|
||||||
|
INVALID_JWKS("invalid_jwks", "Invalid jwks json. Please check if `IdsConfig.JwtConfig.jwksJson` is configured correctly."),
|
||||||
|
INVALID_CODE_CHALLENGE("invalid_code_challenge", "Illegal request, code challenge verification failed."),
|
||||||
|
INVALID_TOKEN("invalid_token", "Invalid token (access token, refresh token, or id token)."),
|
||||||
|
INVALID_SCOPE("invalid_scope", "The requested scope parameter is invalid, unknown, or the requested permission scope exceeds the permission scope granted by the data owner."),
|
||||||
|
INVALID_REDIRECT_URI("invalid_redirect_uri", "The requested callback URL is incorrect."),
|
||||||
|
UNSUPPORTED_GRANT_TYPE("unsupported_grant_type", "The grant type is not supported by the authorization server, or the current client is not authorized for the grant type."),
|
||||||
|
UNSUPPORTED_RESPONSE_TYPE("unsupported_response_type", "The response type is not supported by the authorization server, or the current client does not allow the response type."),
|
||||||
|
ACCESS_DENIED("access_denied", "The authorization server rejected the current request。"),
|
||||||
|
SERVER_ERROR("server_error", "The authorization server is temporarily unavailable. Please try again later."),
|
||||||
|
AUTHORIZATION_FAILED("authorization_failed", "Authorization failed, please contact the systems administrator."),
|
||||||
|
EXPIRED_TOKEN("expired_token", "The requested token has expired (access token, refresh token, or id token)."),
|
||||||
|
DISABLED_CLIENT("disabled_client", "The client is not accessible and may have been disabled by the administrator."),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String error;
|
||||||
|
private final String errorDescription;
|
||||||
|
|
||||||
|
ErrorResponse(String error, String errorDescription) {
|
||||||
|
this.error = error;
|
||||||
|
this.errorDescription = errorDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ErrorResponse getByError(String error) {
|
||||||
|
if (StringUtil.isEmpty(error)) {
|
||||||
|
return AUTHORIZATION_FAILED;
|
||||||
|
}
|
||||||
|
ErrorResponse[] errorResponses = ErrorResponse.values();
|
||||||
|
for (ErrorResponse errorResponse : errorResponses) {
|
||||||
|
if (errorResponse.getError().equalsIgnoreCase(error)) {
|
||||||
|
return errorResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AUTHORIZATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorDescription() {
|
||||||
|
return errorDescription;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model.enums;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* oauth grant type
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public enum GrantType {
|
||||||
|
/**
|
||||||
|
* Authorization code grant
|
||||||
|
*
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-1.3.1" target="_blank">RFC 6749 (OAuth 2.0), 1.3.1. Authorization Code</a>
|
||||||
|
* @see <a href="http://tools.ietf.org/html/rfc6749#section-4.1.3" target="_blank">RFC 6749 (OAuth 2.0), 4.1.3. Access Token Request</a>
|
||||||
|
* @see <a href="http://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint" target="_blank">OpenID Connect Core 1.0, 3.1.3. Token Endpoint</a>
|
||||||
|
*/
|
||||||
|
AUTHORIZATION_CODE("authorization_code"),
|
||||||
|
/**
|
||||||
|
* The implicit grant is a simplified authorization code flow optimized for clients implemented in a browser using a scripting language such as JavaScript.
|
||||||
|
*
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-1.3.2" target="_blank">RFC 6749 (OAuth 2.0), 1.3.2. Implicit</a>
|
||||||
|
*/
|
||||||
|
IMPLICIT("implicit"),
|
||||||
|
/**
|
||||||
|
* The resource owner password credentials (i.e., username and password) can be used directly as an authorization grant to obtain an access token.
|
||||||
|
* The credentials should only be used when there is a <strong>high degree of trust between the resource owner and the client</strong>
|
||||||
|
* (e.g., the client is part of the device operating system or a highly privileged application),
|
||||||
|
* and when other authorization grant types are <strong>not available</strong> (such as an authorization code).
|
||||||
|
*
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-1.3.3" target="_blank">RFC 6749 (OAuth 2.0), 1.3.3. Resource Owner Password Credentials</a>
|
||||||
|
* @see <a href="http://tools.ietf.org/html/rfc6749#section-4.3.2" target="_blank">RFC 6749 (OAuth 2.0), 4.3.2. Access Token Request</a>
|
||||||
|
*/
|
||||||
|
PASSWORD("password"),
|
||||||
|
/**
|
||||||
|
* Client Credentials grant
|
||||||
|
*
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-1.3.4" target="_blank">RFC 6749 (OAuth 2.0), 1.3.4. Client Credentials</a>
|
||||||
|
* @see <a href="http://tools.ietf.org/html/rfc6749#section-4.4.2" target="_blank">RFC 6749 (OAuth 2.0), 4.4.2. Access Token Request</a>
|
||||||
|
*/
|
||||||
|
CLIENT_CREDENTIALS("client_credentials"),
|
||||||
|
/**
|
||||||
|
* The grant type used when refreshing the token
|
||||||
|
*
|
||||||
|
* @see <a href="http://tools.ietf.org/html/rfc6749#section-6" target="_blank">RFC 6749 (OAuth 2.0), 6. Refreshing an Access Token</a>
|
||||||
|
* @see <a href="http://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens" target="_blank">OpenID Connect Core 1.0, 12. Using Refresh Tokens</a>
|
||||||
|
*/
|
||||||
|
REFRESH_TOKEN("refresh_token"),
|
||||||
|
/**
|
||||||
|
* The grant type used when obtaining the access token
|
||||||
|
*/
|
||||||
|
TOKEN("token");
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
GrantType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> grantTypes() {
|
||||||
|
return Arrays.stream(GrantType.values())
|
||||||
|
.map(GrantType::getType)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model.enums;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.config.IdsConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The verification type when the user verifies the jwt token (access token, refresh token, id token),
|
||||||
|
* For specific usage, please refer to {@link com.fujieid.jap.ids.util.JwtUtil#validateJwtToken(String, String, String, IdsConfig)}
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public enum JwtVerificationType {
|
||||||
|
/**
|
||||||
|
* Using an HTTPS JWKS endpoint
|
||||||
|
*/
|
||||||
|
HTTPS_JWKS_ENDPOINT,
|
||||||
|
/**
|
||||||
|
* Using JWKs
|
||||||
|
*/
|
||||||
|
JWKS
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model.enums;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response Type
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public enum ResponseType {
|
||||||
|
/**
|
||||||
|
* https://tools.ietf.org/html/rfc6749#section-3.1.1
|
||||||
|
* https://tools.ietf.org/html/rfc6749#section-4.1.1
|
||||||
|
*/
|
||||||
|
CODE("code"),
|
||||||
|
/**
|
||||||
|
* "token" for requesting an access token (implicit grant) as described
|
||||||
|
* https://tools.ietf.org/html/rfc6749#section-4.2.1
|
||||||
|
*/
|
||||||
|
TOKEN("token"),
|
||||||
|
/**
|
||||||
|
* a registered extension value as described by Section 8.4.
|
||||||
|
* https://tools.ietf.org/html/rfc6749#section-8.4
|
||||||
|
*/
|
||||||
|
ID_TOKEN("id_token"),
|
||||||
|
ID_TOKEN_TOKEN("id_token token"),
|
||||||
|
CODE_ID_TOKEN("code id_token"),
|
||||||
|
CODE_TOKEN("code token"),
|
||||||
|
CODE_ID_TOKEN_TOKEN("code id_token token"),
|
||||||
|
/**
|
||||||
|
* https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#none
|
||||||
|
*/
|
||||||
|
NONE("none");
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
ResponseType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> responseTypes() {
|
||||||
|
return Arrays.stream(ResponseType.values())
|
||||||
|
.map(ResponseType::getType)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When accessing the api, the token usage mode supports the following four situations:
|
||||||
|
* <p>
|
||||||
|
* 1. Set {@code bearer access token} in the request header: {@link TokenAuthMethod#TOKEN_HEADER}
|
||||||
|
* <p>
|
||||||
|
* 2. Set access token in cookie: {@link TokenAuthMethod#TOKEN_COOKIE}
|
||||||
|
* <p>
|
||||||
|
* 3. url: {@link TokenAuthMethod#TOKEN_URL}
|
||||||
|
* <p>
|
||||||
|
* 4. All of the above support:{@link TokenAuthMethod#ALL}
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public enum TokenAuthMethod {
|
||||||
|
/**
|
||||||
|
* request header
|
||||||
|
*/
|
||||||
|
TOKEN_HEADER,
|
||||||
|
/**
|
||||||
|
* cookie
|
||||||
|
*/
|
||||||
|
TOKEN_COOKIE,
|
||||||
|
/**
|
||||||
|
* url
|
||||||
|
*/
|
||||||
|
TOKEN_URL,
|
||||||
|
/**
|
||||||
|
* 支持全部
|
||||||
|
*/
|
||||||
|
ALL
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.model.enums;
|
||||||
|
|
||||||
|
import org.jose4j.keys.EcKeyUtil;
|
||||||
|
import org.jose4j.keys.RsaKeyUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jwt token encryption algorithm, Supports two types of algorithms, RSA and EC
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public enum TokenSigningAlg {
|
||||||
|
/**
|
||||||
|
* RS256
|
||||||
|
*/
|
||||||
|
RS256("RS256", RsaKeyUtil.RSA),
|
||||||
|
RS384("RS384", RsaKeyUtil.RSA),
|
||||||
|
RS512("RS512", RsaKeyUtil.RSA),
|
||||||
|
ES256("ES256", EcKeyUtil.EC),
|
||||||
|
ES384("ES384", EcKeyUtil.EC),
|
||||||
|
ES512("ES512", EcKeyUtil.EC),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String alg;
|
||||||
|
private final String keyType;
|
||||||
|
|
||||||
|
TokenSigningAlg(String alg, String keyType) {
|
||||||
|
this.alg = alg;
|
||||||
|
this.keyType = keyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlg() {
|
||||||
|
return alg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyType() {
|
||||||
|
return keyType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* ids model
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
package com.fujieid.jap.ids.model;
|
209
jap-ids/src/main/java/com/fujieid/jap/ids/oidc/IdToken.java
Normal file
209
jap-ids/src/main/java/com/fujieid/jap/ids/oidc/IdToken.java
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.oidc;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* According to standard specifications, construct id token
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html#IDToken" target="_blank">ID Token</a>
|
||||||
|
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims" target="_blank">Standard Claims</a>
|
||||||
|
* @since 1.0.1
|
||||||
|
*/
|
||||||
|
public class IdToken implements Serializable {
|
||||||
|
/**
|
||||||
|
* {@code iss} - the Issuer identifier
|
||||||
|
*/
|
||||||
|
private String iss;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code sub} - the Subject identifier
|
||||||
|
*/
|
||||||
|
private String sub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code aud} - the Audience(s) that the ID Token is intended for
|
||||||
|
*/
|
||||||
|
private String aud;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code exp} - the Expiration time on or after which the ID Token MUST NOT be accepted
|
||||||
|
*/
|
||||||
|
private Long exp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code iat} - the time at which the ID Token was issued
|
||||||
|
*/
|
||||||
|
private Long iat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code auth_time} - the time when the End-User authentication occurred
|
||||||
|
*/
|
||||||
|
private String auth_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code nonce} - a {@code String} value used to associate a Client session with an ID Token,
|
||||||
|
* and to mitigate replay attacks.
|
||||||
|
*/
|
||||||
|
private String nonce;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code acr} - the Authentication Context Class Reference
|
||||||
|
*/
|
||||||
|
private String acr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code amr} - the Authentication Methods References
|
||||||
|
*/
|
||||||
|
private String amr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code azp} - the Authorized party to which the ID Token was issued
|
||||||
|
*/
|
||||||
|
private String azp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code at_hash} - the Access Token hash value
|
||||||
|
*/
|
||||||
|
private String at_hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code c_hash} - the Authorization Code hash value
|
||||||
|
*/
|
||||||
|
private String c_hash;
|
||||||
|
|
||||||
|
private Object extra;
|
||||||
|
|
||||||
|
public String getIss() {
|
||||||
|
return iss;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setIss(String iss) {
|
||||||
|
this.iss = iss;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSub() {
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setSub(String sub) {
|
||||||
|
this.sub = sub;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAud() {
|
||||||
|
return aud;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setAud(String aud) {
|
||||||
|
this.aud = aud;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getExp() {
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setExp(Long exp) {
|
||||||
|
this.exp = exp;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getIat() {
|
||||||
|
return iat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setIat(Long iat) {
|
||||||
|
this.iat = iat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuth_time() {
|
||||||
|
return auth_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setAuth_time(String auth_time) {
|
||||||
|
this.auth_time = auth_time;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNonce() {
|
||||||
|
return nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setNonce(String nonce) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAcr() {
|
||||||
|
return acr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setAcr(String acr) {
|
||||||
|
this.acr = acr;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAmr() {
|
||||||
|
return amr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setAmr(String amr) {
|
||||||
|
this.amr = amr;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAzp() {
|
||||||
|
return azp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setAzp(String azp) {
|
||||||
|
this.azp = azp;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAt_hash() {
|
||||||
|
return at_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setAt_hash(String at_hash) {
|
||||||
|
this.at_hash = at_hash;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getC_hash() {
|
||||||
|
return c_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setC_hash(String c_hash) {
|
||||||
|
this.c_hash = c_hash;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getExtra() {
|
||||||
|
return extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdToken setExtra(Object extra) {
|
||||||
|
this.extra = extra;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
128
jap-ids/src/main/java/com/fujieid/jap/ids/oidc/OidcUtil.java
Normal file
128
jap-ids/src/main/java/com/fujieid/jap/ids/oidc/OidcUtil.java
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.oidc;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.config.IdsConfig;
|
||||||
|
import com.fujieid.jap.ids.model.IdsConsts;
|
||||||
|
import com.fujieid.jap.ids.model.OidcDiscoveryDto;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ClientSecretAuthMethod;
|
||||||
|
import com.fujieid.jap.ids.model.enums.GrantType;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ResponseType;
|
||||||
|
import com.fujieid.jap.ids.provider.IdsScopeProvider;
|
||||||
|
import com.fujieid.jap.ids.util.JwtUtil;
|
||||||
|
import com.fujieid.jap.ids.util.ObjectUtils;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
import org.jose4j.jwk.JsonWebKey;
|
||||||
|
import org.jose4j.jwk.JsonWebKeySet;
|
||||||
|
import org.jose4j.jwt.ReservedClaimNames;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class OidcUtil {
|
||||||
|
|
||||||
|
public static OidcDiscoveryDto getOidcDiscoveryInfo(String identity, IdsConfig config) {
|
||||||
|
|
||||||
|
List<String> scopes = IdsScopeProvider.getScopeCodes();
|
||||||
|
|
||||||
|
Map<String, Object> model = new HashMap<>();
|
||||||
|
String issuer = config.getIssuer();
|
||||||
|
model.put("issuer", issuer);
|
||||||
|
model.put("authorization_endpoint", ObjectUtils.appendIfNotEndWith(config.getAuthorizeUrl(), identity));
|
||||||
|
model.put("token_endpoint", ObjectUtils.appendIfNotEndWith(config.getTokenUrl(), identity));
|
||||||
|
model.put("userinfo_endpoint", ObjectUtils.appendIfNotEndWith(config.getUserinfoUrl(), identity));
|
||||||
|
model.put("registration_endpoint", ObjectUtils.appendIfNotEndWith(config.getRegistrationUrl(), identity));
|
||||||
|
model.put("end_session_endpoint", ObjectUtils.appendIfNotEndWith(config.getEndSessionUrl(), identity));
|
||||||
|
model.put("check_session_iframe", ObjectUtils.appendIfNotEndWith(config.getCheckSessionUrl(), identity));
|
||||||
|
model.put("jwks_uri", ObjectUtils.appendIfNotEndWith(config.getJwksUrl(), identity));
|
||||||
|
model.put("grant_types_supported", GrantType.grantTypes());
|
||||||
|
model.put("response_modes_supported", Arrays.asList(
|
||||||
|
"fragment",
|
||||||
|
"query"));
|
||||||
|
model.put("response_types_supported", ResponseType.responseTypes());
|
||||||
|
model.put("scopes_supported", scopes);
|
||||||
|
|
||||||
|
List<ClientSecretAuthMethod> clientSecretAuthMethods = config.getClientSecretAuthMethods();
|
||||||
|
if (ObjectUtil.isEmpty(clientSecretAuthMethods)) {
|
||||||
|
clientSecretAuthMethods = Collections.singletonList(ClientSecretAuthMethod.ALL);
|
||||||
|
}
|
||||||
|
if (clientSecretAuthMethods.contains(ClientSecretAuthMethod.ALL)) {
|
||||||
|
model.put("token_endpoint_auth_methods_supported", ClientSecretAuthMethod.getAllMethods());
|
||||||
|
} else {
|
||||||
|
model.put("token_endpoint_auth_methods_supported", clientSecretAuthMethods
|
||||||
|
.stream()
|
||||||
|
.map(ClientSecretAuthMethod::getMethod)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
model.put("request_object_signing_alg_values_supported", Arrays.asList(
|
||||||
|
"none",
|
||||||
|
"RS256",
|
||||||
|
"ES256"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
model.put("userinfo_signing_alg_values_supported", Arrays.asList(
|
||||||
|
"RS256",
|
||||||
|
"ES256"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
model.put("request_parameter_supported", true);
|
||||||
|
model.put("request_uri_parameter_supported", true);
|
||||||
|
model.put("require_request_uri_registration", false);
|
||||||
|
model.put("claims_parameter_supported", true);
|
||||||
|
model.put("id_token_signing_alg_values_supported", Arrays.asList(
|
||||||
|
"RS256",
|
||||||
|
"ES256"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
model.put("subject_types_supported", Collections.singletonList("public"));
|
||||||
|
model.put("claims_supported", Arrays.asList(
|
||||||
|
ReservedClaimNames.ISSUER,
|
||||||
|
ReservedClaimNames.SUBJECT,
|
||||||
|
ReservedClaimNames.AUDIENCE,
|
||||||
|
ReservedClaimNames.EXPIRATION_TIME,
|
||||||
|
ReservedClaimNames.ISSUED_AT,
|
||||||
|
IdsConsts.NONCE,
|
||||||
|
IdsConsts.AUTH_TIME,
|
||||||
|
IdsConsts.USERNAME
|
||||||
|
));
|
||||||
|
model.put("code_challenge_methods_supported", Arrays.asList(
|
||||||
|
"PLAIN",
|
||||||
|
"S256"
|
||||||
|
));
|
||||||
|
return BeanUtil.mapToBean(model, OidcDiscoveryDto.class, false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getJwksPublicKey(String identity, IdsConfig idsConfig) {
|
||||||
|
String jwksJson = null;
|
||||||
|
if (StringUtil.isNotEmpty(identity)) {
|
||||||
|
jwksJson = JapIds.getContext().getIdentityService().getJwksJson(identity);
|
||||||
|
} else {
|
||||||
|
jwksJson = idsConfig.getJwtConfig().getJwksJson();
|
||||||
|
}
|
||||||
|
JsonWebKeySet jsonWebKeySet = JwtUtil.IdsVerificationKeyResolver.createJsonWebKeySet(jwksJson);
|
||||||
|
return jsonWebKeySet.toJson(JsonWebKey.OutputControlLevel.PUBLIC_ONLY);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Support openid connect
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
package com.fujieid.jap.ids.oidc;
|
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Authorization service based on rfc6749 protocol specification and OpenID Connect Core 1.0 specification
|
* Authorization service based on RFC6749 protocol specification and OpenID Connect Core 1.0 specification
|
||||||
* <p>
|
* <p>
|
||||||
* Features:
|
* Features:
|
||||||
* <p>
|
* <p>
|
||||||
@ -43,6 +43,7 @@
|
|||||||
* @see <a href="https://tools.ietf.org/html/rfc6749" target="_blank"> The OAuth 2.0 Authorization Framework</a>
|
* @see <a href="https://tools.ietf.org/html/rfc6749" target="_blank"> The OAuth 2.0 Authorization Framework</a>
|
||||||
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html" target="_blank">OpenID Connect Core 1.0 incorporating errata set 1</a>
|
* @see <a href="https://openid.net/specs/openid-connect-core-1_0.html" target="_blank">OpenID Connect Core 1.0 incorporating errata set 1</a>
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc7636" target="_blank">Proof Key for Code Exchange by OAuth Public Clients</a>
|
* @see <a href="https://tools.ietf.org/html/rfc7636" target="_blank">Proof Key for Code Exchange by OAuth Public Clients</a>
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc7033" target="_blank">WebFinger</a>
|
||||||
* @see <a href="https://openid.net/specs/openid-connect-discovery-1_0.html" target="_blank">OpenID Connect Discovery 1.0 incorporating errata set 1</a>
|
* @see <a href="https://openid.net/specs/openid-connect-discovery-1_0.html" target="_blank">OpenID Connect Discovery 1.0 incorporating errata set 1</a>
|
||||||
* @see <a href="https://openid.net/specs/openid-connect-frontchannel-1_0.html" target="_blank">OpenID Connect Front-Channel Logout 1.0</a>
|
* @see <a href="https://openid.net/specs/openid-connect-frontchannel-1_0.html" target="_blank">OpenID Connect Front-Channel Logout 1.0</a>
|
||||||
* @see <a href="https://openid.net/specs/openid-connect-backchannel-1_0.html" target="_blank">OpenID Connect Back-Channel Logout 1.0</a>
|
* @see <a href="https://openid.net/specs/openid-connect-backchannel-1_0.html" target="_blank">OpenID Connect Back-Channel Logout 1.0</a>
|
||||||
|
@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.provider;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.*;
|
||||||
|
import com.fujieid.jap.ids.service.Oauth2Service;
|
||||||
|
import com.fujieid.jap.ids.util.OauthUtil;
|
||||||
|
import com.fujieid.jap.ids.util.ObjectUtils;
|
||||||
|
import com.fujieid.jap.ids.util.TokenUtil;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorize the endpoint to create a callback url, and pass different callback parameters according to the request parameters
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsAuthorizationProvider {
|
||||||
|
|
||||||
|
private final Oauth2Service oauth2Service;
|
||||||
|
|
||||||
|
public IdsAuthorizationProvider(Oauth2Service oauth2Service) {
|
||||||
|
this.oauth2Service = oauth2Service;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4.2. Implicit Grant
|
||||||
|
*
|
||||||
|
* @param userInfo Logged-in user information
|
||||||
|
* @param param Request parameter
|
||||||
|
* @param clientDetail Application information
|
||||||
|
* @return String
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.2">4.2. Implicit Grant</a>
|
||||||
|
*/
|
||||||
|
public String generateImplicitGrantResponse(UserInfo userInfo, IdsRequestParam param, ClientDetail clientDetail) {
|
||||||
|
AccessToken accessToken = TokenUtil.createAccessToken(userInfo, clientDetail, param.getGrantType(), param.getScope(), param.getNonce());
|
||||||
|
Map<String, String> tokenResponse = new HashMap<>(9);
|
||||||
|
// https://tools.ietf.org/html/rfc6749#section-4.2.2
|
||||||
|
// The authorization server MUST NOT issue a refresh token.
|
||||||
|
tokenResponse.put(IdsConsts.ACCESS_TOKEN, accessToken.getAccessToken());
|
||||||
|
tokenResponse.put(IdsConsts.EXPIRES_IN, String.valueOf(OauthUtil.getAccessTokenExpiresIn(clientDetail.getAccessTokenExpiresIn())));
|
||||||
|
tokenResponse.put(IdsConsts.TOKEN_TYPE, IdsConsts.TOKEN_TYPE_BEARER);
|
||||||
|
tokenResponse.put(IdsConsts.SCOPE, param.getScope());
|
||||||
|
if (OauthUtil.isOidcProtocol(param.getScope())) {
|
||||||
|
tokenResponse.put(IdsConsts.ID_TOKEN, TokenUtil.createIdToken(clientDetail, userInfo, param.getNonce()));
|
||||||
|
}
|
||||||
|
if (StringUtil.isNotEmpty(param.getState())) {
|
||||||
|
tokenResponse.put(IdsConsts.STATE, param.getState());
|
||||||
|
}
|
||||||
|
String params = ObjectUtils.parseMapToString(tokenResponse, false);
|
||||||
|
return param.getRedirectUri() + "?" + params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4.1. Authorization Code Grant
|
||||||
|
*
|
||||||
|
* @param userInfo Logged-in user information
|
||||||
|
* @param param Request parameter
|
||||||
|
* @param clientDetail Application information
|
||||||
|
* @return String
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.1">4.1. Authorization Code Grant</a>
|
||||||
|
*/
|
||||||
|
public String generateAuthorizationCodeResponse(UserInfo userInfo, IdsRequestParam param, ClientDetail clientDetail) {
|
||||||
|
String authorizationCode = oauth2Service.createAuthorizationCode(param, userInfo, OauthUtil.getCodeExpiresIn(clientDetail.getCodeExpiresIn()));
|
||||||
|
String params = "?code=" + authorizationCode;
|
||||||
|
if (StringUtil.isNotEmpty(param.getState())) {
|
||||||
|
params = params + "&state=" + param.getState();
|
||||||
|
}
|
||||||
|
return param.getRedirectUri() + params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the value of {@code response_type} is {@code code id_token}, return {@code code} and {@code id_token} from the authorization endpoint
|
||||||
|
*
|
||||||
|
* @param userInfo Logged-in user information
|
||||||
|
* @param param Request parameter
|
||||||
|
* @param clientDetail Application information
|
||||||
|
* @return String
|
||||||
|
* @see <a href="https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Combinations">Definitions of Multiple-Valued Response Type Combinations</a>
|
||||||
|
*/
|
||||||
|
public String generateCodeIdTokenAuthorizationResponse(UserInfo userInfo, IdsRequestParam param, ClientDetail clientDetail) {
|
||||||
|
String params = "&id_token=" + TokenUtil.createIdToken(clientDetail, userInfo, param.getNonce());
|
||||||
|
return this.generateAuthorizationCodeResponse(userInfo, param, clientDetail) + params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the value of {@code response_type} is {@code id_token}, an {@code id_token} is returned from the authorization endpoint.
|
||||||
|
* This mode does not require the use of token endpoints.
|
||||||
|
*
|
||||||
|
* @param userInfo Logged-in user information
|
||||||
|
* @param param Request parameter
|
||||||
|
* @param clientDetail Application information
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String generateIdTokenAuthorizationResponse(UserInfo userInfo, IdsRequestParam param, ClientDetail clientDetail) {
|
||||||
|
String params = "?id_token=" + TokenUtil.createIdToken(clientDetail, userInfo, param.getNonce());
|
||||||
|
return param.getRedirectUri() + params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the value of {@code response_type} is {@code id_token token}, the {@code id_token} and {@code access_token} are returned from the authorization endpoint.
|
||||||
|
* This mode does not require the use of token endpoints.
|
||||||
|
*
|
||||||
|
* @param userInfo Logged-in user information
|
||||||
|
* @param param Request parameter
|
||||||
|
* @param clientDetail Application information
|
||||||
|
* @return String
|
||||||
|
* @see <a href="https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Combinations">Definitions of Multiple-Valued Response Type Combinations</a>
|
||||||
|
*/
|
||||||
|
public String generateIdTokenTokenAuthorizationResponse(UserInfo userInfo, IdsRequestParam param, ClientDetail clientDetail) {
|
||||||
|
AccessToken accessToken = TokenUtil.createAccessToken(userInfo, clientDetail, param.getGrantType(), param.getScope(), param.getNonce());
|
||||||
|
String params = "?access_token=" + accessToken.getAccessToken() + "&id_token=" + TokenUtil.createIdToken(clientDetail, userInfo, param.getNonce());
|
||||||
|
return param.getRedirectUri() + params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the value of {@code response_type} is {@code code token}, return {@code code} and {@code token} from the authorization endpoint
|
||||||
|
*
|
||||||
|
* @param userInfo Logged-in user information
|
||||||
|
* @param param Request parameter
|
||||||
|
* @param clientDetail Application information
|
||||||
|
* @return String
|
||||||
|
* @see <a href="https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Combinations">Definitions of Multiple-Valued Response Type Combinations</a>
|
||||||
|
*/
|
||||||
|
public String generateCodeTokenAuthorizationResponse(UserInfo userInfo, IdsRequestParam param, ClientDetail clientDetail) {
|
||||||
|
AccessToken accessToken = TokenUtil.createAccessToken(userInfo, clientDetail, param.getGrantType(), param.getScope(), param.getNonce());
|
||||||
|
String params = "&access_token=" + accessToken.getAccessToken();
|
||||||
|
return this.generateAuthorizationCodeResponse(userInfo, param, clientDetail) + params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the value of {@code response_type} is {@code code id_token token}, return {@code code},{@code id_token} and {@code token} from the authorization endpoint
|
||||||
|
*
|
||||||
|
* @param userInfo Logged-in user information
|
||||||
|
* @param param Request parameter
|
||||||
|
* @param clientDetail Application information
|
||||||
|
* @return String
|
||||||
|
* @see <a href="https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Combinations">Definitions of Multiple-Valued Response Type Combinations</a>
|
||||||
|
*/
|
||||||
|
public String generateCodeIdTokenTokenAuthorizationResponse(UserInfo userInfo, IdsRequestParam param, ClientDetail clientDetail) {
|
||||||
|
String params = "&id_token=" + TokenUtil.createIdToken(clientDetail, userInfo, param.getNonce());
|
||||||
|
return this.generateCodeTokenAuthorizationResponse(userInfo, param, clientDetail) + params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the value of {@code response_type} is {@code none}, the {@code code},{@code id_token} and {@code token} is not returned from the authorization endpoint,
|
||||||
|
* if there is a state, it is returned as it is.
|
||||||
|
*
|
||||||
|
* @param param Request parameter
|
||||||
|
* @return String
|
||||||
|
* @see <a href="https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#none">None Response Type</a>
|
||||||
|
*/
|
||||||
|
public String generateNoneAuthorizationResponse(IdsRequestParam param) {
|
||||||
|
String params = "";
|
||||||
|
if (!StringUtil.isEmpty(param.getState())) {
|
||||||
|
params = "?state=" + param.getState();
|
||||||
|
}
|
||||||
|
return param.getRedirectUri() + params;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.provider;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidRequestException;
|
||||||
|
import com.fujieid.jap.ids.model.ClientCertificate;
|
||||||
|
import com.fujieid.jap.ids.model.IdsConsts;
|
||||||
|
import com.fujieid.jap.ids.model.IdsRequestParam;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.util.ClientCertificateUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter parser for oauth request
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsRequestParamProvider {
|
||||||
|
|
||||||
|
public static IdsRequestParam parseRequest(HttpServletRequest request) {
|
||||||
|
if (ObjectUtil.isEmpty(request.getParameterMap())) {
|
||||||
|
throw new InvalidRequestException(ErrorResponse.INVALID_REQUEST);
|
||||||
|
}
|
||||||
|
IdsRequestParam param = new IdsRequestParam();
|
||||||
|
|
||||||
|
ClientCertificate clientCertificate = ClientCertificateUtil.getClientCertificate(request);
|
||||||
|
param.setClientId(clientCertificate.getId());
|
||||||
|
param.setClientSecret(clientCertificate.getSecret());
|
||||||
|
|
||||||
|
param.setCode(request.getParameter(IdsConsts.CODE));
|
||||||
|
param.setRedirectUri(request.getParameter(IdsConsts.REDIRECT_URI));
|
||||||
|
param.setScope(request.getParameter(IdsConsts.SCOPE));
|
||||||
|
param.setState(request.getParameter(IdsConsts.STATE));
|
||||||
|
param.setGrantType(request.getParameter(IdsConsts.GRANT_TYPE));
|
||||||
|
param.setAccessToken(request.getParameter(IdsConsts.ACCESS_TOKEN));
|
||||||
|
param.setRefreshToken(request.getParameter(IdsConsts.REFRESH_TOKEN));
|
||||||
|
param.setResponseType(request.getParameter(IdsConsts.RESPONSE_TYPE));
|
||||||
|
param.setNonce(request.getParameter(IdsConsts.NONCE));
|
||||||
|
param.setUid(request.getParameter(IdsConsts.UID));
|
||||||
|
|
||||||
|
param.setResponseMode(request.getParameter(IdsConsts.RESPONSE_MODE));
|
||||||
|
param.setDisplay(request.getParameter(IdsConsts.DISPLAY));
|
||||||
|
param.setPrompt(request.getParameter(IdsConsts.PROMPT));
|
||||||
|
param.setAuthTime(request.getParameter(IdsConsts.MAX_AGE));
|
||||||
|
param.setIdTokenHint(request.getParameter(IdsConsts.ID_TOKEN_HINT));
|
||||||
|
param.setAcr(request.getParameter(IdsConsts.ACR));
|
||||||
|
param.setAutoapprove(request.getParameter(IdsConsts.AUTOAPPROVE));
|
||||||
|
|
||||||
|
// Get username and password Applies to:<a href="https://tools.ietf.org/html/rfc6749#section-4.3" target="_blank">Resource Owner Password Credentials Grant</a>
|
||||||
|
param.setUsername(request.getParameter(IdsConsts.USERNAME));
|
||||||
|
param.setPassword(request.getParameter(IdsConsts.PASSWORD));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Applicable to open pkce enhanced protocol in authorization code mode
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc7636" target="_blank">Proof Key for Code Exchange by OAuth Public Clients</a>
|
||||||
|
*/
|
||||||
|
param.setCodeVerifier(request.getParameter(IdsConsts.CODE_VERIFIER));
|
||||||
|
param.setCodeChallengeMethod(request.getParameter(IdsConsts.CODE_CHALLENGE_METHOD));
|
||||||
|
param.setCodeChallenge(request.getParameter(IdsConsts.CODE_CHALLENGE));
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.provider;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.fujieid.jap.ids.model.IdsScope;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define and manage the scope used in oauth authorization.
|
||||||
|
* Read, write, openid, email, and phone are supported by default.
|
||||||
|
* If developers need to modify the scope, they can use the following methods:
|
||||||
|
* <p>
|
||||||
|
* {@link com.fujieid.jap.ids.provider.IdsScopeProvider#initScopes(List)}
|
||||||
|
* <p>
|
||||||
|
* {@link com.fujieid.jap.ids.provider.IdsScopeProvider#addScope(IdsScope)}
|
||||||
|
* <p>
|
||||||
|
* Note: Whether it is a custom scope or a system built-in scope, openid must be included, which is a required option for enabling OIDC
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsScopeProvider {
|
||||||
|
|
||||||
|
private static List<IdsScope> scopes = new ArrayList<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
addScope(new IdsScope().setCode("read").setDescription("Allows to read resources, including users, protected resources, etc."));
|
||||||
|
addScope(new IdsScope().setCode("write").setDescription("Allows to modify resources, including adding, deleting, and modifying resources such as users and protected resources."));
|
||||||
|
addScope(new IdsScope().setCode("openid").setDescription("OpenID connect must include scope"));
|
||||||
|
addScope(new IdsScope().setCode("email").setDescription("Allow access to user's mailbox"));
|
||||||
|
addScope(new IdsScope().setCode("phone").setDescription("Allow access to the user’s phone number"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize scope
|
||||||
|
* <p>
|
||||||
|
* Note: This method will reset the existing scope collection
|
||||||
|
*
|
||||||
|
* @param idsScopes scope collection
|
||||||
|
*/
|
||||||
|
public static void initScopes(List<IdsScope> idsScopes) {
|
||||||
|
if (ObjectUtil.isNotEmpty(idsScopes)) {
|
||||||
|
scopes = idsScopes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a single scope.
|
||||||
|
* Note: This method is to add data to the existing scope collection
|
||||||
|
*
|
||||||
|
* @param idsScope single scope
|
||||||
|
*/
|
||||||
|
public static void addScope(IdsScope idsScope) {
|
||||||
|
scopes.add(idsScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the set of available scopes after deduplication according to the scope code
|
||||||
|
*
|
||||||
|
* @return Unique scope collection
|
||||||
|
*/
|
||||||
|
public static List<IdsScope> getScopes() {
|
||||||
|
return scopes.stream().collect(Collectors.collectingAndThen(
|
||||||
|
Collectors.toCollection(() -> new TreeSet<>(
|
||||||
|
Comparator.comparing(
|
||||||
|
IdsScope::getCode))), ArrayList::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the scope collection through scope code (does not contain duplicates)
|
||||||
|
*
|
||||||
|
* @param codes scope code
|
||||||
|
* @return Unique scope collection
|
||||||
|
*/
|
||||||
|
public static List<IdsScope> getScopeByCodes(Collection<String> codes) {
|
||||||
|
if (ObjectUtil.isEmpty(codes)) {
|
||||||
|
return new ArrayList<>(0);
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(scopes.stream().filter((scope) -> codes.contains(scope.getCode()))
|
||||||
|
.collect(Collectors.collectingAndThen(
|
||||||
|
Collectors.toCollection(() -> new TreeSet<>(
|
||||||
|
Comparator.comparing(
|
||||||
|
IdsScope::getCode))), ArrayList::new)))
|
||||||
|
.orElse(new ArrayList<>(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the code of all scopes
|
||||||
|
*
|
||||||
|
* @return code of all scopes
|
||||||
|
*/
|
||||||
|
public static List<String> getScopeCodes() {
|
||||||
|
return scopes.stream().map(IdsScope::getCode).distinct().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.provider;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.exception.IdsException;
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidClientException;
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidRequestException;
|
||||||
|
import com.fujieid.jap.ids.model.*;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.model.enums.GrantType;
|
||||||
|
import com.fujieid.jap.ids.service.Oauth2Service;
|
||||||
|
import com.fujieid.jap.ids.util.OauthUtil;
|
||||||
|
import com.fujieid.jap.ids.util.TokenUtil;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The token endpoint creates a token, and returns different token information for different authorization types
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class IdsTokenProvider {
|
||||||
|
|
||||||
|
private final Oauth2Service oauth2Service;
|
||||||
|
|
||||||
|
public IdsTokenProvider(Oauth2Service oauth2Service) {
|
||||||
|
this.oauth2Service = oauth2Service;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RFC6749 4.1. authorization code grant
|
||||||
|
*
|
||||||
|
* @param param request params
|
||||||
|
* @return IdsResponse
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.1" target="_blank">4.1. Authorization Code Grant</a>
|
||||||
|
*/
|
||||||
|
public IdsResponse<String, Object> generateAuthorizationCodeResponse(IdsRequestParam param) {
|
||||||
|
AuthCode codeInfo = oauth2Service.validateAndGetAuthrizationCode(param.getGrantType(), param.getCode());
|
||||||
|
|
||||||
|
String scope = codeInfo.getScope();
|
||||||
|
UserInfo userInfo = codeInfo.getUser();
|
||||||
|
String nonce = codeInfo.getNonce();
|
||||||
|
|
||||||
|
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId());
|
||||||
|
|
||||||
|
OauthUtil.validClientDetail(clientDetail);
|
||||||
|
OauthUtil.validateGrantType(param.getGrantType(), clientDetail.getGrantTypes(), GrantType.AUTHORIZATION_CODE);
|
||||||
|
OauthUtil.validateSecret(param, clientDetail, oauth2Service);
|
||||||
|
OauthUtil.validateRedirectUri(param.getRedirectUri(), clientDetail);
|
||||||
|
|
||||||
|
oauth2Service.invalidateCode(param.getCode());
|
||||||
|
|
||||||
|
long expiresIn = OauthUtil.getAccessTokenExpiresIn(clientDetail.getAccessTokenExpiresIn());
|
||||||
|
|
||||||
|
AccessToken accessToken = TokenUtil.createAccessToken(userInfo, clientDetail, param.getGrantType(), scope, nonce);
|
||||||
|
IdsResponse<String, Object> response = new IdsResponse<String, Object>()
|
||||||
|
.add(IdsConsts.ACCESS_TOKEN, accessToken.getAccessToken())
|
||||||
|
.add(IdsConsts.REFRESH_TOKEN, accessToken.getRefreshToken())
|
||||||
|
.add(IdsConsts.EXPIRES_IN, expiresIn)
|
||||||
|
.add(IdsConsts.TOKEN_TYPE, IdsConsts.TOKEN_TYPE_BEARER)
|
||||||
|
.add(IdsConsts.SCOPE, scope);
|
||||||
|
if (OauthUtil.isOidcProtocol(scope)) {
|
||||||
|
response.add(IdsConsts.ID_TOKEN, TokenUtil.createIdToken(clientDetail, userInfo, nonce));
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RFC6749 4.3. Resource Owner Password Credentials Grant
|
||||||
|
*
|
||||||
|
* @param param request params
|
||||||
|
* @return IdsResponse
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.3" target="_blank">4.3. Resource Owner Password Credentials Grant</a>
|
||||||
|
*/
|
||||||
|
public IdsResponse<String, Object> generatePasswordResponse(IdsRequestParam param) {
|
||||||
|
|
||||||
|
if (ObjectUtil.hasNull(param.getClientId())) {
|
||||||
|
throw new InvalidClientException(ErrorResponse.INVALID_CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
String username = param.getUsername();
|
||||||
|
String password = param.getPassword();
|
||||||
|
UserInfo userInfo = JapIds.getContext().getUserService().loginByUsernameAndPassword(username, password);
|
||||||
|
if (null == userInfo) {
|
||||||
|
throw new IdsException(ErrorResponse.INVALID_USER_CERTIFICATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(param.getClientId());
|
||||||
|
String requestScope = param.getScope();
|
||||||
|
|
||||||
|
OauthUtil.validClientDetail(clientDetail);
|
||||||
|
OauthUtil.validateScope(requestScope, clientDetail.getScopes());
|
||||||
|
OauthUtil.validateGrantType(param.getGrantType(), clientDetail.getGrantTypes(), GrantType.PASSWORD);
|
||||||
|
OauthUtil.validateSecret(param, clientDetail, oauth2Service);
|
||||||
|
|
||||||
|
long expiresIn = OauthUtil.getAccessTokenExpiresIn(clientDetail.getAccessTokenExpiresIn());
|
||||||
|
|
||||||
|
AccessToken accessToken = TokenUtil.createAccessToken(userInfo, clientDetail, param.getGrantType(), requestScope, param.getNonce());
|
||||||
|
IdsResponse<String, Object> response = new IdsResponse<String, Object>()
|
||||||
|
.add(IdsConsts.ACCESS_TOKEN, accessToken.getAccessToken())
|
||||||
|
.add(IdsConsts.REFRESH_TOKEN, accessToken.getRefreshToken())
|
||||||
|
.add(IdsConsts.EXPIRES_IN, expiresIn)
|
||||||
|
.add(IdsConsts.TOKEN_TYPE, IdsConsts.TOKEN_TYPE_BEARER)
|
||||||
|
.add(IdsConsts.SCOPE, requestScope);
|
||||||
|
|
||||||
|
if (OauthUtil.isOidcProtocol(requestScope)) {
|
||||||
|
response.add(IdsConsts.ID_TOKEN, TokenUtil.createIdToken(clientDetail, userInfo, param.getNonce()));
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RFC6749 4.4. Client Credentials Grant
|
||||||
|
*
|
||||||
|
* @param param request params
|
||||||
|
* @return IdsResponse
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-4.4" target="_blank">4.4. Client Credentials Grant</a>
|
||||||
|
*/
|
||||||
|
public IdsResponse<String, Object> generateClientCredentialsResponse(IdsRequestParam param) {
|
||||||
|
String clientId = param.getClientId();
|
||||||
|
|
||||||
|
if (ObjectUtil.hasNull(param.getClientId(), param.getClientSecret())) {
|
||||||
|
throw new InvalidClientException(ErrorResponse.INVALID_CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(clientId);
|
||||||
|
String requestScope = param.getScope();
|
||||||
|
|
||||||
|
OauthUtil.validClientDetail(clientDetail);
|
||||||
|
OauthUtil.validateScope(requestScope, clientDetail.getScopes());
|
||||||
|
OauthUtil.validateGrantType(param.getGrantType(), clientDetail.getGrantTypes(), GrantType.CLIENT_CREDENTIALS);
|
||||||
|
OauthUtil.validateSecret(param, clientDetail, oauth2Service);
|
||||||
|
|
||||||
|
long expiresIn = OauthUtil.getAccessTokenExpiresIn(clientDetail.getAccessTokenExpiresIn());
|
||||||
|
|
||||||
|
AccessToken accessToken = TokenUtil.createClientCredentialsAccessToken(clientDetail, param.getGrantType(), requestScope, param.getNonce());
|
||||||
|
|
||||||
|
// https://tools.ietf.org/html/rfc6749#section-4.2.2
|
||||||
|
// The authorization server MUST NOT issue a refresh token.
|
||||||
|
IdsResponse<String, Object> response = new IdsResponse<String, Object>()
|
||||||
|
.add(IdsConsts.ACCESS_TOKEN, accessToken.getAccessToken())
|
||||||
|
.add(IdsConsts.EXPIRES_IN, expiresIn)
|
||||||
|
.add(IdsConsts.TOKEN_TYPE, IdsConsts.TOKEN_TYPE_BEARER);
|
||||||
|
if (!StringUtil.isEmpty(requestScope)) {
|
||||||
|
response.add(IdsConsts.SCOPE, requestScope);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RFC6749 6. Refreshing an Access Token
|
||||||
|
*
|
||||||
|
* @param param request params
|
||||||
|
* @return IdsResponse
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc6749#section-6" target="_blank">6. Refreshing an Access Token</a>
|
||||||
|
*/
|
||||||
|
public IdsResponse<String, Object> generateRefreshTokenResponse(IdsRequestParam param) {
|
||||||
|
TokenUtil.validateRefreshToken(param.getRefreshToken());
|
||||||
|
|
||||||
|
try {
|
||||||
|
AccessToken token = TokenUtil.getByRefreshToken(param.getRefreshToken());
|
||||||
|
|
||||||
|
ClientDetail clientDetail = JapIds.getContext().getClientDetailService().getByClientId(token.getClientId());
|
||||||
|
String requestScope = param.getScope();
|
||||||
|
|
||||||
|
OauthUtil.validClientDetail(clientDetail);
|
||||||
|
OauthUtil.validateScope(requestScope, clientDetail.getScopes());
|
||||||
|
OauthUtil.validateGrantType(param.getGrantType(), clientDetail.getGrantTypes(), GrantType.REFRESH_TOKEN);
|
||||||
|
OauthUtil.validateSecret(param, clientDetail, oauth2Service);
|
||||||
|
|
||||||
|
UserInfo user = JapIds.getContext().getUserService().getById(token.getUserId());
|
||||||
|
|
||||||
|
long expiresIn = OauthUtil.getRefreshTokenExpiresIn(clientDetail.getRefreshTokenExpiresIn());
|
||||||
|
|
||||||
|
AccessToken accessToken = TokenUtil.refreshAccessToken(user, clientDetail, token, param.getNonce());
|
||||||
|
return new IdsResponse<String, Object>()
|
||||||
|
.add(IdsConsts.ACCESS_TOKEN, accessToken.getAccessToken())
|
||||||
|
.add(IdsConsts.REFRESH_TOKEN, accessToken.getRefreshToken())
|
||||||
|
.add(IdsConsts.EXPIRES_IN, expiresIn)
|
||||||
|
.add(IdsConsts.TOKEN_TYPE, IdsConsts.TOKEN_TYPE_BEARER)
|
||||||
|
.add(IdsConsts.SCOPE, requestScope);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidRequestException(ErrorResponse.SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Provide oauth service
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
package com.fujieid.jap.ids.provider;
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.service;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.exception.IdsException;
|
||||||
|
import com.fujieid.jap.ids.model.ClientDetail;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client application related interfaces
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public interface IdsClientDetailService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query client information through client id
|
||||||
|
*
|
||||||
|
* @param clientId Client application id
|
||||||
|
* @return ClientDetail
|
||||||
|
*/
|
||||||
|
default ClientDetail getByClientId(String clientId) {
|
||||||
|
throw new IdsException("Not implemented `IdsClientDetailService.getByClientId(String)`");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add client
|
||||||
|
*
|
||||||
|
* @param clientDetail Client application details
|
||||||
|
* @return ClientDetail
|
||||||
|
*/
|
||||||
|
default ClientDetail add(ClientDetail clientDetail) {
|
||||||
|
throw new IdsException("Not implemented `IdsClientDetailService.add(ClientDetail)`");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modify the client
|
||||||
|
*
|
||||||
|
* @param clientDetail Client application details
|
||||||
|
* @return ClientDetail
|
||||||
|
*/
|
||||||
|
default ClientDetail update(ClientDetail clientDetail) {
|
||||||
|
throw new IdsException("Not implemented `IdsClientDetailService.update(ClientDetail)`");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete client by primary key
|
||||||
|
*
|
||||||
|
* @param id Primary key of the client application
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
default boolean removeById(String id) {
|
||||||
|
throw new IdsException("Not implemented `IdsClientDetailService.removeById(String)`");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete client by client id
|
||||||
|
*
|
||||||
|
* @param clientId Client application id
|
||||||
|
* @return ClientDetail
|
||||||
|
*/
|
||||||
|
default boolean removeByClientId(String clientId) {
|
||||||
|
throw new IdsException("Not implemented `IdsClientDetailService.removeByClientId(String)`");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all client detail
|
||||||
|
*
|
||||||
|
* @return List
|
||||||
|
*/
|
||||||
|
default List<ClientDetail> getAllClientDetail() {
|
||||||
|
throw new IdsException("Not implemented `IdsClientDetailService.getAllClientDetail()`");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.service;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.config.JwtConfig;
|
||||||
|
import com.fujieid.jap.ids.exception.IdsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User/organization/enterprise and other identity service related interfaces
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public interface IdsIdentityService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the jwt token encryption key string
|
||||||
|
*
|
||||||
|
* @param identity User/organization/enterprise identification
|
||||||
|
* @return Encryption key string in json format
|
||||||
|
*/
|
||||||
|
default String getJwksJson(String identity) {
|
||||||
|
throw new IdsException("Not implemented `IdsIdentityService.getJwksJson(String)`");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configuration of jwt token encryption
|
||||||
|
*
|
||||||
|
* @param identity User/organization/enterprise identification
|
||||||
|
* @return Encryption key string in json format
|
||||||
|
*/
|
||||||
|
default JwtConfig getJwtConfig(String identity) {
|
||||||
|
throw new IdsException("Not implemented `IdsIdentityService.getJwtConfig(String)`");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.service;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.exception.IdsException;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User-related interface
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public interface IdsUserService {
|
||||||
|
|
||||||
|
default UserInfo loginByUsernameAndPassword(String username, String password) {
|
||||||
|
throw new IdsException("Not implemented `IdsUserService.loginByUsernameAndPassword(String, String)`");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user info by userid.
|
||||||
|
*
|
||||||
|
* @param userId userId of the business system
|
||||||
|
* @return JapUser
|
||||||
|
*/
|
||||||
|
default UserInfo getById(String userId) {
|
||||||
|
throw new IdsException("Not implemented `IdsUserService.getById(String)`");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user info by username.
|
||||||
|
*
|
||||||
|
* @param username username of the business system
|
||||||
|
* @return JapUser
|
||||||
|
*/
|
||||||
|
default UserInfo getByName(String username) {
|
||||||
|
throw new IdsException("Not implemented `IdsUserService.getByName(String)`");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.service;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.AuthCode;
|
||||||
|
import com.fujieid.jap.ids.model.IdsRequestParam;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* oauth 2.0 related methods
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public interface Oauth2Service {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate authorization code
|
||||||
|
*
|
||||||
|
* @param param Parameters requested by the client
|
||||||
|
* @param user User Info
|
||||||
|
* @param codeExpiresIn code expiration time
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
String createAuthorizationCode(IdsRequestParam param, UserInfo user, Long codeExpiresIn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verification authorization code
|
||||||
|
*
|
||||||
|
* @param grantType grant Type
|
||||||
|
* @param code authorization code
|
||||||
|
* @return AuthCode
|
||||||
|
*/
|
||||||
|
AuthCode validateAndGetAuthrizationCode(String grantType, String code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the pkce protocol is enabled, the code challenge needs to be verified
|
||||||
|
*
|
||||||
|
* @param codeVerifier code verifier
|
||||||
|
* @param code authorization code
|
||||||
|
* @see <a href="https://tools.ietf.org/html/rfc7636">https://tools.ietf.org/html/rfc7636</a>
|
||||||
|
*/
|
||||||
|
void validateAuthrizationCodeChallenge(String codeVerifier, String code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain auth code info by authorization code
|
||||||
|
*
|
||||||
|
* @param code authorization code
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
AuthCode getCodeInfo(String code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete authorization code
|
||||||
|
*
|
||||||
|
* @param code authorization code
|
||||||
|
*/
|
||||||
|
void invalidateCode(String code);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import cn.hutool.log.LogFactory;
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidCodeException;
|
||||||
|
import com.fujieid.jap.ids.model.AuthCode;
|
||||||
|
import com.fujieid.jap.ids.model.IdsConsts;
|
||||||
|
import com.fujieid.jap.ids.model.IdsRequestParam;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.model.enums.GrantType;
|
||||||
|
import com.fujieid.jap.ids.util.OauthUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* oauth 2.0 related methods
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class Oauth2ServiceImpl implements Oauth2Service {
|
||||||
|
private static final Log log = LogFactory.get();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createAuthorizationCode(IdsRequestParam param, UserInfo user, Long codeExpiresIn) {
|
||||||
|
String scopeStr = param.getScope();
|
||||||
|
String nonce = param.getNonce();
|
||||||
|
String code = RandomUtil.randomString(12);
|
||||||
|
|
||||||
|
AuthCode authCode = new AuthCode()
|
||||||
|
.setScope(scopeStr)
|
||||||
|
.setUser(user)
|
||||||
|
.setNonce(nonce)
|
||||||
|
.setCodeChallenge(param.getCodeChallenge())
|
||||||
|
.setCodeChallengeMethod(param.getCodeChallengeMethod());
|
||||||
|
JapIds.getContext().getCache().set(IdsConsts.OAUTH_CODE_CACHE_KEY + code, authCode, codeExpiresIn * 1000);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthCode validateAndGetAuthrizationCode(String grantType, String code) {
|
||||||
|
if (!GrantType.AUTHORIZATION_CODE.getType().equals(grantType)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AuthCode authCode = this.getCodeInfo(code);
|
||||||
|
if (null == authCode || ObjectUtil.hasNull(authCode.getUser(), authCode.getScope())) {
|
||||||
|
throw new InvalidCodeException(ErrorResponse.INVALID_CODE);
|
||||||
|
}
|
||||||
|
return authCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateAuthrizationCodeChallenge(String codeVerifier, String code) {
|
||||||
|
log.debug("客户端开启了 PKCE 增强协议,开始校验 code challenge 的合法性...");
|
||||||
|
AuthCode authCode = this.getCodeInfo(code);
|
||||||
|
if (ObjectUtil.isNull(authCode)) {
|
||||||
|
throw new InvalidCodeException(ErrorResponse.INVALID_CODE);
|
||||||
|
}
|
||||||
|
if (ObjectUtil.hasNull(authCode.getCodeChallenge(), authCode.getCodeChallengeMethod())) {
|
||||||
|
log.debug("客户端开启了 PKCE 增强协议,code challenge 的合法性,校验失败...");
|
||||||
|
throw new InvalidCodeException(ErrorResponse.INVALID_CODE_CHALLENGE);
|
||||||
|
}
|
||||||
|
String codeChallengeMethod = authCode.getCodeChallengeMethod();
|
||||||
|
String cacheCodeChallenge = authCode.getCodeChallenge();
|
||||||
|
String currentCodeChallenge = OauthUtil.generateCodeChallenge(codeChallengeMethod, codeVerifier);
|
||||||
|
if (!currentCodeChallenge.equals(cacheCodeChallenge)) {
|
||||||
|
throw new InvalidCodeException(ErrorResponse.INVALID_CODE_CHALLENGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthCode getCodeInfo(String code) {
|
||||||
|
return (AuthCode) JapIds.getContext().getCache().get(IdsConsts.OAUTH_CODE_CACHE_KEY + code);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidateCode(String code) {
|
||||||
|
JapIds.getContext().getCache().removeKey(IdsConsts.OAUTH_CODE_CACHE_KEY + code);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* The interface exposed by ids needs to be implemented by the caller
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
package com.fujieid.jap.ids.service;
|
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.util;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.ClientCertificate;
|
||||||
|
import org.jose4j.base64url.internal.apache.commons.codec.binary.Base64;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credentials in Basic authentication.
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @see <a href="http://tools.ietf.org/html/rfc2617#section-2">RFC 2617 (HTTP Authentication), 2. Basic Authentication Scheme</a>
|
||||||
|
*/
|
||||||
|
public class BasicCredentials {
|
||||||
|
/**
|
||||||
|
* Regular expression to parse {@code Authorization} header.
|
||||||
|
*/
|
||||||
|
private static final Pattern CHALLENGE_PATTERN = Pattern.compile("^Basic *([^ ]+) *$", Pattern.CASE_INSENSITIVE);
|
||||||
|
private final ClientCertificate clientCertificate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Basic {base64-encoded id:secret}"
|
||||||
|
*/
|
||||||
|
private transient String formatted;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor with credentials.
|
||||||
|
*
|
||||||
|
* @param id The client ID.
|
||||||
|
* @param secret The client secret.
|
||||||
|
*/
|
||||||
|
public BasicCredentials(String id, String secret) {
|
||||||
|
this.clientCertificate = new ClientCertificate(null == id ? "" : id, null == secret ? "" : secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse {@code Authorization} header for Basic authentication.
|
||||||
|
*
|
||||||
|
* @param input The value of {@code Authorization} header. Expected inputs
|
||||||
|
* are either <code>"Basic <i>{Base64-Encoded-id-and-secret}</i>"</code>,
|
||||||
|
* or <code>"<i>{Base64-Encoded-id-and-secret}</i>"</code>.
|
||||||
|
* @return Parsed credentials. If {@code input} is {@code null} is returned.
|
||||||
|
*/
|
||||||
|
public static BasicCredentials parse(String input) {
|
||||||
|
if (input == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher matcher = CHALLENGE_PATTERN.matcher(input);
|
||||||
|
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
return new BasicCredentials(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
String encoded = matcher.group(1);
|
||||||
|
byte[] decoded = Base64.decodeBase64(encoded);
|
||||||
|
String value = new String(decoded, StandardCharsets.UTF_8);
|
||||||
|
String[] credentials = value.split(":", 2);
|
||||||
|
|
||||||
|
String id = credentials[0];
|
||||||
|
String secret = null;
|
||||||
|
if (credentials.length == 2) {
|
||||||
|
secret = credentials[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BasicCredentials(id, secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return clientCertificate.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSecret() {
|
||||||
|
return clientCertificate.getSecret();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientCertificate getClientCertificate() {
|
||||||
|
return clientCertificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a value suitable as the value of {@code Authorization} header.
|
||||||
|
*
|
||||||
|
* @return {@code Authorization} header value for Basic authentication.
|
||||||
|
*/
|
||||||
|
public String create() {
|
||||||
|
if (formatted != null) {
|
||||||
|
return formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
String credentials = String.format("%s:%s", clientCertificate.getId(), clientCertificate.getSecret());
|
||||||
|
|
||||||
|
byte[] credentialsBytes = credentials.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
String encoded = Base64.encodeBase64String(credentialsBytes);
|
||||||
|
|
||||||
|
return (formatted = "Basic " + encoded);
|
||||||
|
}
|
||||||
|
}
|
146
jap-ids/src/main/java/com/fujieid/jap/ids/util/BearerToken.java
Normal file
146
jap-ids/src/main/java/com/fujieid/jap/ids/util/BearerToken.java
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Authlete, Inc.
|
||||||
|
*
|
||||||
|
* 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 com.fujieid.jap.ids.util;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.model.IdsConsts;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for Bearer Token defined in
|
||||||
|
* <a href="http://tools.ietf.org/html/rfc6750">RFC 6750</a>.
|
||||||
|
*
|
||||||
|
* @author Takahiko Kawasaki
|
||||||
|
* @see <a href="http://tools.ietf.org/html/rfc6750">RFC 6750 (OAuth 2.0 Bearer Token Usage)</a>
|
||||||
|
*/
|
||||||
|
public class BearerToken {
|
||||||
|
/**
|
||||||
|
* Regular expression to parse {@code Authorization} header.
|
||||||
|
*/
|
||||||
|
private static final Pattern CHALLENGE_PATTERN
|
||||||
|
= Pattern.compile("^Bearer *([^ ]+) *$", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
|
||||||
|
private BearerToken() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the access token embedded in the input string.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This method assumes that the input string comes from one of
|
||||||
|
* the following three places that are mentioned in "RFC 6750
|
||||||
|
* (OAuth 2.0 Bearer Token Usage),
|
||||||
|
* <a href="http://tools.ietf.org/html/rfc6750#section-2"
|
||||||
|
* >2. Authenticated Requests</a>".
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <blockquote>
|
||||||
|
* <ol>
|
||||||
|
* <li><a href="http://tools.ietf.org/html/rfc6750#section-2.1"
|
||||||
|
* >Authorization Request Header Field</a>
|
||||||
|
* <li><a href="http://tools.ietf.org/html/rfc6750#section-2.2"
|
||||||
|
* >Form-Encoded Body Parameter</a>
|
||||||
|
* <li><a href="http://tools.ietf.org/html/rfc6750#section-2.3"
|
||||||
|
* >URI Query Parameter</a>
|
||||||
|
* </ol>
|
||||||
|
* </blockquote>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* To be concrete, this method assumes that the format of the
|
||||||
|
* input string is either of the following two.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <blockquote>
|
||||||
|
* <ol>
|
||||||
|
* <li><code>"Bearer <i>{access-token}</i>"</code>
|
||||||
|
* <li>Parameters formatted in <code>application/x-www-form-urlencoded</code>
|
||||||
|
* containing <code>access_token=<i>{access-token}</i></code>.
|
||||||
|
* </ol>
|
||||||
|
* </blockquote>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For example, both {@link BearerToken#parse(String) parse} method calls below
|
||||||
|
* return <code>"hello-world"</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* BearerToken.parse("Bearer hello-world");
|
||||||
|
* BearerToken.parse("key1=value1&access_token=hello-world");
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param input The input string to be parsed.
|
||||||
|
* @return The extracted access token, or <code>null</code> if not found.
|
||||||
|
* @see <a href="http://tools.ietf.org/html/rfc6750"
|
||||||
|
* >RFC 6750 (OAuth 2.0 Bearer Token Usage)</a>
|
||||||
|
*/
|
||||||
|
public static String parse(String input) {
|
||||||
|
if (input == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input.startsWith(IdsConsts.TOKEN_TYPE_BEARER) && !input.contains("&")) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, check whether the input matches the pattern
|
||||||
|
// "Bearer {access-token}".
|
||||||
|
Matcher matcher = CHALLENGE_PATTERN.matcher(input);
|
||||||
|
|
||||||
|
// If the input matches the pattern.
|
||||||
|
if (matcher.matches()) {
|
||||||
|
// Return the value as is. Note that it is not Base64-encoded.
|
||||||
|
// See https://www.ietf.org/mail-archive/web/oauth/current/msg08489.html
|
||||||
|
return matcher.group(1);
|
||||||
|
} else {
|
||||||
|
// Assume that the input is formatted in
|
||||||
|
// application/x-www-form-urlencoded.
|
||||||
|
return extractFromFormParameters(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String extractFromFormParameters(String input) {
|
||||||
|
for (String parameter : input.split("&")) {
|
||||||
|
String[] pair = parameter.split("=", 2);
|
||||||
|
|
||||||
|
if (pair.length != 2 || pair[1].length() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!"access_token".equals(pair[0])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// URL-decode
|
||||||
|
return URLDecoder.decode(pair[1], "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
// This won't happen.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.fujieid.jap.core.util.RequestUtil;
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.model.ClientCertificate;
|
||||||
|
import com.fujieid.jap.ids.model.IdsConsts;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ClientSecretAuthMethod;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the client secret, client id from the request
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class ClientCertificateUtil {
|
||||||
|
|
||||||
|
public static ClientCertificate getClientCertificate(HttpServletRequest request) {
|
||||||
|
List<ClientSecretAuthMethod> clientSecretAuthMethods = JapIds.getIdsConfig().getClientSecretAuthMethods();
|
||||||
|
if (ObjectUtil.isEmpty(clientSecretAuthMethods)) {
|
||||||
|
clientSecretAuthMethods = Collections.singletonList(ClientSecretAuthMethod.ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientSecretAuthMethods.contains(ClientSecretAuthMethod.ALL)) {
|
||||||
|
ClientCertificate clientCertificate = getClientCertificateFromRequestParameter(request);
|
||||||
|
if (StringUtil.isEmpty(clientCertificate.getId())) {
|
||||||
|
clientCertificate = getClientCertificateFromHeader(request);
|
||||||
|
}
|
||||||
|
return clientCertificate;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (clientSecretAuthMethods.contains(ClientSecretAuthMethod.CLIENT_SECRET_POST)
|
||||||
|
|| clientSecretAuthMethods.contains(ClientSecretAuthMethod.NONE)) {
|
||||||
|
return getClientCertificateFromRequestParameter(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientSecretAuthMethods.contains(ClientSecretAuthMethod.CLIENT_SECRET_BASIC)) {
|
||||||
|
return getClientCertificateFromHeader(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ClientCertificate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClientCertificate getClientCertificateFromRequestParameter(HttpServletRequest request) {
|
||||||
|
String clientId = RequestUtil.getParam(IdsConsts.CLIENT_ID, request);
|
||||||
|
String clientSecret = RequestUtil.getParam(IdsConsts.CLIENT_SECRET, request);
|
||||||
|
return new ClientCertificate(clientId, clientSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClientCertificate getClientCertificateFromHeader(HttpServletRequest request) {
|
||||||
|
String authorizationHeader = RequestUtil.getHeader(IdsConsts.AUTHORIZATION_HEADER_NAME, request);
|
||||||
|
if (StringUtil.isNotEmpty(authorizationHeader)) {
|
||||||
|
BasicCredentials credentials = BasicCredentials.parse(authorizationHeader);
|
||||||
|
return credentials.getClientCertificate();
|
||||||
|
}
|
||||||
|
return new ClientCertificate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
51
jap-ids/src/main/java/com/fujieid/jap/ids/util/DateUtil.java
Normal file
51
jap-ids/src/main/java/com/fujieid/jap/ids/util/DateUtil.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.util;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class DateUtil extends cn.hutool.core.date.DateUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert timestamp to LocalDateTime
|
||||||
|
*
|
||||||
|
* @param second Long type timestamp, in seconds
|
||||||
|
* @param zoneOffset Time zone, default is {@code +8}
|
||||||
|
* @return java.time.LocalDateTime
|
||||||
|
*/
|
||||||
|
public static LocalDateTime ofEpochSecond(Long second, ZoneOffset zoneOffset) {
|
||||||
|
if (zoneOffset == null) {
|
||||||
|
return LocalDateTime.ofEpochSecond(second, 0, ZoneOffset.ofHours(8));
|
||||||
|
} else {
|
||||||
|
return LocalDateTime.ofEpochSecond(second, 0, zoneOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current Date
|
||||||
|
*
|
||||||
|
* @return LocalDateTime
|
||||||
|
*/
|
||||||
|
public static LocalDateTime nowDate() {
|
||||||
|
return LocalDateTime.now();
|
||||||
|
}
|
||||||
|
}
|
129
jap-ids/src/main/java/com/fujieid/jap/ids/util/JwkUtil.java
Normal file
129
jap-ids/src/main/java/com/fujieid/jap/ids/util/JwkUtil.java
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.util;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidJwksException;
|
||||||
|
import com.fujieid.jap.ids.model.enums.TokenSigningAlg;
|
||||||
|
import org.jose4j.jwk.*;
|
||||||
|
import org.jose4j.keys.EllipticCurves;
|
||||||
|
import org.jose4j.lang.JoseException;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate json web key encryption certificate
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class JwkUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create rsa json web key
|
||||||
|
*
|
||||||
|
* @param keyId key id
|
||||||
|
* @param signingAlg Encryption Algorithm
|
||||||
|
* @return RsaJsonWebKey
|
||||||
|
*/
|
||||||
|
public static RsaJsonWebKey createRsaJsonWebKey(String keyId, TokenSigningAlg signingAlg) {
|
||||||
|
if (!Arrays.asList(TokenSigningAlg.RS256, TokenSigningAlg.RS384, TokenSigningAlg.RS512).contains(signingAlg)) {
|
||||||
|
throw new InvalidJwksException("Unable to create RSA Json Web Key. Unsupported jwk algorithm, only supports RS256, RS384, RS512");
|
||||||
|
}
|
||||||
|
RsaJsonWebKey jwk = null;
|
||||||
|
try {
|
||||||
|
jwk = RsaJwkGenerator.generateJwk(2048);
|
||||||
|
jwk.setKeyId(keyId);
|
||||||
|
jwk.setAlgorithm(signingAlg.getAlg());
|
||||||
|
} catch (JoseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new InvalidJwksException("Unable to create RSA Json Web Key.");
|
||||||
|
}
|
||||||
|
return jwk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the json string of rsa json web key
|
||||||
|
*
|
||||||
|
* @param keyId key id
|
||||||
|
* @param signingAlg Encryption Algorithm
|
||||||
|
* @return RSA Json Web Key Json
|
||||||
|
*/
|
||||||
|
public static String createRsaJsonWebKeyJson(String keyId, TokenSigningAlg signingAlg) {
|
||||||
|
RsaJsonWebKey jwk = createRsaJsonWebKey(keyId, signingAlg);
|
||||||
|
return jwk.toJson(RsaJsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a set collection of rsa json web key json string
|
||||||
|
*
|
||||||
|
* @param keyId key id
|
||||||
|
* @param signingAlg Encryption Algorithm
|
||||||
|
* @return RSA Json Web Key Set Json
|
||||||
|
*/
|
||||||
|
public static String createRsaJsonWebKeySetJson(String keyId, TokenSigningAlg signingAlg) {
|
||||||
|
RsaJsonWebKey jwk = createRsaJsonWebKey(keyId, signingAlg);
|
||||||
|
return new JsonWebKeySet(jwk).toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create es json web key
|
||||||
|
*
|
||||||
|
* @param keyId key id
|
||||||
|
* @param signingAlg Encryption Algorithm
|
||||||
|
* @return Elliptic Curve Json Web Key
|
||||||
|
*/
|
||||||
|
public static EllipticCurveJsonWebKey createEsJsonWebKey(String keyId, TokenSigningAlg signingAlg) {
|
||||||
|
if (!Arrays.asList(TokenSigningAlg.ES256, TokenSigningAlg.ES384, TokenSigningAlg.ES512).contains(signingAlg)) {
|
||||||
|
throw new InvalidJwksException("Unable to create ES Json Web Key. Unsupported jwk algorithm, only supports ES256, ES384, ES512");
|
||||||
|
}
|
||||||
|
EllipticCurveJsonWebKey jwk = null;
|
||||||
|
try {
|
||||||
|
jwk = EcJwkGenerator.generateJwk(EllipticCurves.P256);
|
||||||
|
jwk.setUse(Use.SIGNATURE);
|
||||||
|
jwk.setKeyId(keyId);
|
||||||
|
jwk.setAlgorithm(signingAlg.getAlg());
|
||||||
|
} catch (JoseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new InvalidJwksException("Unable to create ES Json Web Key.");
|
||||||
|
}
|
||||||
|
return jwk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create json string of es json web key
|
||||||
|
*
|
||||||
|
* @param keyId key id
|
||||||
|
* @param signingAlg Encryption Algorithm
|
||||||
|
* @return ES Json Web Key Json
|
||||||
|
*/
|
||||||
|
public static String createEsJsonWebKeyJson(String keyId, TokenSigningAlg signingAlg) {
|
||||||
|
EllipticCurveJsonWebKey jwk = createEsJsonWebKey(keyId, signingAlg);
|
||||||
|
return jwk.toJson(RsaJsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a set collection of es json web key json string
|
||||||
|
*
|
||||||
|
* @param keyId key id
|
||||||
|
* @param signingAlg Encryption Algorithm
|
||||||
|
* @return RS Json Web Key Set Json
|
||||||
|
*/
|
||||||
|
public static String createEsJsonWebKeySetJson(String keyId, TokenSigningAlg signingAlg) {
|
||||||
|
EllipticCurveJsonWebKey jwk = createEsJsonWebKey(keyId, signingAlg);
|
||||||
|
return new JsonWebKeySet(jwk).toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);
|
||||||
|
}
|
||||||
|
}
|
280
jap-ids/src/main/java/com/fujieid/jap/ids/util/JwtUtil.java
Normal file
280
jap-ids/src/main/java/com/fujieid/jap/ids/util/JwtUtil.java
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.util;
|
||||||
|
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import cn.hutool.log.LogFactory;
|
||||||
|
import com.fujieid.jap.ids.config.IdsConfig;
|
||||||
|
import com.fujieid.jap.ids.config.JwtConfig;
|
||||||
|
import com.fujieid.jap.ids.exception.IdsTokenException;
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidJwksException;
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidTokenException;
|
||||||
|
import com.fujieid.jap.ids.model.IdsConsts;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.model.enums.JwtVerificationType;
|
||||||
|
import com.fujieid.jap.ids.model.enums.TokenSigningAlg;
|
||||||
|
import com.xkcoding.json.JsonUtil;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
import org.jose4j.jwk.*;
|
||||||
|
import org.jose4j.jws.JsonWebSignature;
|
||||||
|
import org.jose4j.jwt.JwtClaims;
|
||||||
|
import org.jose4j.jwt.MalformedClaimException;
|
||||||
|
import org.jose4j.jwt.NumericDate;
|
||||||
|
import org.jose4j.jwt.consumer.InvalidJwtException;
|
||||||
|
import org.jose4j.jwt.consumer.JwtConsumer;
|
||||||
|
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
|
||||||
|
import org.jose4j.keys.EcKeyUtil;
|
||||||
|
import org.jose4j.keys.RsaKeyUtil;
|
||||||
|
import org.jose4j.keys.resolvers.HttpsJwksVerificationKeyResolver;
|
||||||
|
import org.jose4j.keys.resolvers.JwksVerificationKeyResolver;
|
||||||
|
import org.jose4j.keys.resolvers.VerificationKeyResolver;
|
||||||
|
import org.jose4j.lang.JoseException;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* simple JSON Web Key generator:https://mkjwk.org/?spm=a2c4g.11186623.2.33.4b2040ecxvsKD7
|
||||||
|
* <p>
|
||||||
|
* JWT Decoder: http://jwt.calebb.net/
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class JwtUtil {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://bitbucket.org/b_c/jose4j/wiki/JWT%20Examples
|
||||||
|
*
|
||||||
|
* @param clientId Client Identifier
|
||||||
|
* @param userinfo User Profile
|
||||||
|
* @param tokenExpireIn Id Token validity (seconds)
|
||||||
|
* @param nonce noncestr
|
||||||
|
* @param idsConfig ids config
|
||||||
|
* @return jwt token
|
||||||
|
*/
|
||||||
|
public static String createJwtToken(String clientId, UserInfo userinfo, Long tokenExpireIn, String nonce, IdsConfig idsConfig) {
|
||||||
|
JwtClaims claims = new JwtClaims();
|
||||||
|
|
||||||
|
// required
|
||||||
|
// A unique identity of the person providing the authentication information. Usually an HTTPS URL (excl. queryString and Fragment)
|
||||||
|
claims.setIssuer(idsConfig.getIssuer());
|
||||||
|
// The LOGO of EU provided by ISS is unique within the scope of ISS. It is used by the RP to identify a unique user. The maximum length is 255 ASCII characters
|
||||||
|
claims.setSubject(null == userinfo ? clientId : userinfo.getId());
|
||||||
|
// Identify the audience for ID Token. OAuth2's client_ID must be included
|
||||||
|
claims.setAudience(clientId);
|
||||||
|
// Expiration time. ID Token beyond this time will become invalid and will no longer be authenticated
|
||||||
|
claims.setExpirationTime(NumericDate.fromMilliseconds(System.currentTimeMillis() + (tokenExpireIn * 1000)));
|
||||||
|
// JWT build time
|
||||||
|
claims.setIssuedAt(NumericDate.fromMilliseconds(System.currentTimeMillis()));
|
||||||
|
|
||||||
|
// optional
|
||||||
|
// The random string provided by the RP when it sends a request is used to mitigate replay attacks, and the ID Token can also be associated with the RP's own Session
|
||||||
|
if (!StringUtil.isEmpty(nonce)) {
|
||||||
|
claims.setStringClaim(IdsConsts.NONCE, nonce);
|
||||||
|
}
|
||||||
|
if (null != userinfo) {
|
||||||
|
// Time of completion of EU certification. This Claim is required if the RP carries the max_AGE parameter when sending the AuthN request
|
||||||
|
// claims.setClaim("auth_time", "auth_time");
|
||||||
|
// If you include other claim reference: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
|
||||||
|
claims.setStringClaim("username", userinfo.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
// A JWT is a JWS and/or a JWE with JSON claims as the payload.
|
||||||
|
// In this example it is a JWS so we create a JsonWebSignature object.
|
||||||
|
JsonWebSignature jws = new JsonWebSignature();
|
||||||
|
|
||||||
|
// The payload of the JWS is JSON content of the JWT Claims
|
||||||
|
jws.setPayload(claims.toJson());
|
||||||
|
|
||||||
|
JwtConfig jwtConfig = idsConfig.getJwtConfig();
|
||||||
|
PublicJsonWebKey publicJsonWebKey = IdsVerificationKeyResolver.createPublicJsonWebKey(jwtConfig.getJwksKeyId(), jwtConfig.getJwksJson(), jwtConfig.getTokenSigningAlg());
|
||||||
|
if (null == publicJsonWebKey) {
|
||||||
|
throw new InvalidJwksException("Unable to create Jwt Token: Unable to create public json web key.");
|
||||||
|
}
|
||||||
|
// The JWT is signed using the private key
|
||||||
|
jws.setKey(publicJsonWebKey.getPrivateKey());
|
||||||
|
|
||||||
|
// Set the Key ID (kid) header because it's just the polite thing to do.
|
||||||
|
// We only have one key in this example but a using a Key ID helps
|
||||||
|
// facilitate a smooth key rollover process
|
||||||
|
jws.setKeyIdHeaderValue(publicJsonWebKey.getKeyId());
|
||||||
|
|
||||||
|
// Set the signature algorithm on the JWT/JWS that will integrity protect the claims
|
||||||
|
jws.setAlgorithmHeaderValue(jwtConfig.getTokenSigningAlg().getAlg());
|
||||||
|
|
||||||
|
String idToken = null;
|
||||||
|
|
||||||
|
// Sign the JWS and produce the compact serialization or the complete JWT/JWS
|
||||||
|
// representation, which is a string consisting of three dot ('.') separated
|
||||||
|
// base64url-encoded parts in the form Header.Payload.Signature
|
||||||
|
// If you wanted to encrypt it, you can simply set this jwt as the payload
|
||||||
|
// of a JsonWebEncryption object and set the cty (Content Type) header to "jwt".
|
||||||
|
try {
|
||||||
|
idToken = jws.getCompactSerialization();
|
||||||
|
} catch (JoseException e) {
|
||||||
|
throw new IdsTokenException("Unable to create Jwt Token: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return idToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> parseJwtToken(String jwtToken, IdsConfig idsConfig) {
|
||||||
|
JwtConfig jwtConfig = idsConfig.getJwtConfig();
|
||||||
|
|
||||||
|
PublicJsonWebKey publicJsonWebKey = IdsVerificationKeyResolver.createPublicJsonWebKey(jwtConfig.getJwksKeyId(), jwtConfig.getJwksJson(), jwtConfig.getTokenSigningAlg());
|
||||||
|
if (null == publicJsonWebKey) {
|
||||||
|
throw new InvalidJwksException("Unable to parse Jwt Token: Unable to create public json web key.");
|
||||||
|
}
|
||||||
|
JwtConsumer jwtConsumer = new JwtConsumerBuilder()
|
||||||
|
.setSkipDefaultAudienceValidation()
|
||||||
|
// whom the JWT needs to have been issued by
|
||||||
|
// allow some leeway in validating time based claims to account for clock skew
|
||||||
|
.setAllowedClockSkewInSeconds(30)
|
||||||
|
// verify the signature with the public key
|
||||||
|
.setVerificationKey(publicJsonWebKey.getPublicKey())
|
||||||
|
// create the JwtConsumer instance
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Validate the JWT and process it to the Claims
|
||||||
|
JwtClaims jwtClaims = jwtConsumer.processToClaims(jwtToken);
|
||||||
|
return jwtClaims.getClaimsMap();
|
||||||
|
|
||||||
|
} catch (InvalidJwtException e) {
|
||||||
|
// InvalidJwtException will be thrown, if the JWT failed processing or validation in anyway.
|
||||||
|
// Hopefully with meaningful explanations(s) about what went wrong.
|
||||||
|
log.error("Invalid Jwt Token : " + JsonUtil.toJsonString(e.getErrorDetails()), e);
|
||||||
|
if (e.hasExpired()) {
|
||||||
|
throw new InvalidTokenException(ErrorResponse.EXPIRED_TOKEN);
|
||||||
|
}
|
||||||
|
throw new InvalidTokenException(ErrorResponse.INVALID_TOKEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> validateJwtToken(String clientId, String userId, String jwtToken, IdsConfig idsConfig) {
|
||||||
|
// Use JwtConsumerBuilder to construct an appropriate JwtConsumer, which will
|
||||||
|
// be used to validate and process the JWT.
|
||||||
|
// The specific validation requirements for a JWT are context dependent, however,
|
||||||
|
// it typically advisable to require a (reasonable) expiration time, a trusted issuer, and
|
||||||
|
// and audience that identifies your system as the intended recipient.
|
||||||
|
// If the JWT is encrypted too, you need only provide a decryption key or
|
||||||
|
// decryption key resolver to the builder.
|
||||||
|
JwtConfig jwtConfig = idsConfig.getJwtConfig();
|
||||||
|
JwtConsumerBuilder jwtConsumerBuilder = new JwtConsumerBuilder();
|
||||||
|
|
||||||
|
JwtVerificationType jwtVerificationType = jwtConfig.getJwtVerificationType();
|
||||||
|
if (null != jwtVerificationType) {
|
||||||
|
if (jwtVerificationType == JwtVerificationType.HTTPS_JWKS_ENDPOINT) {
|
||||||
|
// The HttpsJwks retrieves and caches keys from a the given HTTPS JWKS endpoint.
|
||||||
|
// Because it retains the JWKs after fetching them, it can and should be reused
|
||||||
|
// to improve efficiency by reducing the number of outbound calls the the endpoint.
|
||||||
|
VerificationKeyResolver verificationKeyResolver = new HttpsJwksVerificationKeyResolver(new HttpsJwks(idsConfig.getJwksUrl()));
|
||||||
|
jwtConsumerBuilder.setVerificationKeyResolver(verificationKeyResolver);
|
||||||
|
} else if (jwtVerificationType == JwtVerificationType.JWKS) {
|
||||||
|
// There's also a key resolver that selects from among a given list of JWKs using the Key ID
|
||||||
|
// and other factors provided in the header of the JWS/JWT.
|
||||||
|
JsonWebKeySet jsonWebKeySet = IdsVerificationKeyResolver.createJsonWebKeySet(jwtConfig.getJwksJson());
|
||||||
|
JwksVerificationKeyResolver jwksResolver = new JwksVerificationKeyResolver(jsonWebKeySet.getJsonWebKeys());
|
||||||
|
jwtConsumerBuilder.setVerificationKeyResolver(jwksResolver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PublicJsonWebKey publicJsonWebKey = IdsVerificationKeyResolver.createPublicJsonWebKey(jwtConfig.getJwksKeyId(), jwtConfig.getJwksJson(), jwtConfig.getTokenSigningAlg());
|
||||||
|
if (null == publicJsonWebKey) {
|
||||||
|
throw new InvalidJwksException("Unable to verify Jwt Token: Unable to create public json web key.");
|
||||||
|
}
|
||||||
|
JwtConsumer jwtConsumer = jwtConsumerBuilder
|
||||||
|
.setRequireIssuedAt()
|
||||||
|
// the JWT must have an expiration time
|
||||||
|
.setRequireExpirationTime()
|
||||||
|
// the JWT must have a subject claim
|
||||||
|
.setRequireSubject()
|
||||||
|
// whom the JWT needs to have been issued by
|
||||||
|
.setExpectedIssuer(idsConfig.getIssuer())
|
||||||
|
.setExpectedSubject(StringUtil.isEmpty(userId) ? clientId : userId)
|
||||||
|
// to whom the JWT is intended for
|
||||||
|
.setExpectedAudience(clientId)
|
||||||
|
// allow some leeway in validating time based claims to account for clock skew
|
||||||
|
.setAllowedClockSkewInSeconds(30)
|
||||||
|
// verify the signature with the public key
|
||||||
|
.setVerificationKey(publicJsonWebKey.getPublicKey())
|
||||||
|
// create the JwtConsumer instance
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Validate the JWT and process it to the Claims
|
||||||
|
JwtClaims jwtClaims = jwtConsumer.processToClaims(jwtToken);
|
||||||
|
return jwtClaims.getClaimsMap();
|
||||||
|
|
||||||
|
} catch (InvalidJwtException e) {
|
||||||
|
// InvalidJwtException will be thrown, if the JWT failed processing or validation in anyway.
|
||||||
|
// Hopefully with meaningful explanations(s) about what went wrong.
|
||||||
|
log.error("Invalid Jwt Token! ", e);
|
||||||
|
|
||||||
|
// Programmatic access to (some) specific reasons for JWT invalidity is also possible
|
||||||
|
// should you want different error handling behavior for certain conditions.
|
||||||
|
|
||||||
|
// Whether or not the JWT has expired being one common reason for invalidity
|
||||||
|
if (e.hasExpired()) {
|
||||||
|
try {
|
||||||
|
log.error("Jwt Token expired at " + e.getJwtContext().getJwtClaims().getExpirationTime());
|
||||||
|
} catch (MalformedClaimException malformedClaimException) {
|
||||||
|
malformedClaimException.printStackTrace();
|
||||||
|
}
|
||||||
|
throw new InvalidTokenException(ErrorResponse.EXPIRED_TOKEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidTokenException(ErrorResponse.INVALID_TOKEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class IdsVerificationKeyResolver {
|
||||||
|
|
||||||
|
public static JsonWebKeySet createJsonWebKeySet(String jwksJson) {
|
||||||
|
InvalidJwksException invalidJwksException = new InvalidJwksException(ErrorResponse.INVALID_JWKS);
|
||||||
|
if (StringUtil.isEmpty(jwksJson)) {
|
||||||
|
throw invalidJwksException;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonWebKeySet jsonWebKeySet = null;
|
||||||
|
try {
|
||||||
|
jsonWebKeySet = new JsonWebKeySet(jwksJson);
|
||||||
|
} catch (JoseException e) {
|
||||||
|
throw invalidJwksException;
|
||||||
|
}
|
||||||
|
return jsonWebKeySet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PublicJsonWebKey createPublicJsonWebKey(String keyId, String jwksJson, TokenSigningAlg tokenSigningAlg) {
|
||||||
|
tokenSigningAlg = null == tokenSigningAlg ? TokenSigningAlg.RS256 : tokenSigningAlg;
|
||||||
|
JsonWebKeySet jsonWebKeySet = createJsonWebKeySet(jwksJson);
|
||||||
|
|
||||||
|
switch (tokenSigningAlg.getKeyType()) {
|
||||||
|
case RsaKeyUtil.RSA:
|
||||||
|
return (RsaJsonWebKey) jsonWebKeySet.findJsonWebKey(keyId, tokenSigningAlg.getKeyType(), Use.SIGNATURE, tokenSigningAlg.getAlg());
|
||||||
|
case EcKeyUtil.EC:
|
||||||
|
return (EllipticCurveJsonWebKey) jsonWebKeySet.findJsonWebKey(keyId, tokenSigningAlg.getKeyType(), Use.SIGNATURE, tokenSigningAlg.getAlg());
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
358
jap-ids/src/main/java/com/fujieid/jap/ids/util/OauthUtil.java
Normal file
358
jap-ids/src/main/java/com/fujieid/jap/ids/util/OauthUtil.java
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.URLUtil;
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import com.fujieid.jap.ids.exception.*;
|
||||||
|
import com.fujieid.jap.ids.model.ClientDetail;
|
||||||
|
import com.fujieid.jap.ids.model.IdsConsts;
|
||||||
|
import com.fujieid.jap.ids.model.IdsRequestParam;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.model.enums.GrantType;
|
||||||
|
import com.fujieid.jap.ids.service.Oauth2Service;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class OauthUtil {
|
||||||
|
private static final Collection<String> REDIRECT_GRANT_TYPES = Arrays.asList("implicit", "authorization_code");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert string to list
|
||||||
|
*
|
||||||
|
* @param text The string to be converted
|
||||||
|
* @param splitRegex Regular expression to split string
|
||||||
|
* @return List of strings (de-duplicated)
|
||||||
|
*/
|
||||||
|
public static Set<String> convertStrToList(String text, String splitRegex) {
|
||||||
|
Set<String> result = new TreeSet<>();
|
||||||
|
if (text != null && text.trim().length() > 0) {
|
||||||
|
String[] tokens = text.split(splitRegex);
|
||||||
|
result.addAll(Arrays.asList(tokens));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert string to list
|
||||||
|
*
|
||||||
|
* @param text The string to be converted
|
||||||
|
* @return List of strings (de-duplicated)
|
||||||
|
*/
|
||||||
|
public static Set<String> convertStrToList(String text) {
|
||||||
|
return convertStrToList(text, "[\\s+]");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param requestScopes The scope parameter in the current request
|
||||||
|
* @param clientScopes Scope in client detail
|
||||||
|
* @return After the verification is passed, return the scope list
|
||||||
|
*/
|
||||||
|
public static Set<String> validateScope(String requestScopes, String clientScopes) {
|
||||||
|
|
||||||
|
if (StringUtil.isEmpty(requestScopes)) {
|
||||||
|
throw new InvalidScopeException("Empty scope (either the client or the user is not allowed the requested scopes)");
|
||||||
|
}
|
||||||
|
Set<String> scopes = OauthUtil.convertStrToList(requestScopes);
|
||||||
|
|
||||||
|
if (StringUtil.isNotEmpty(clientScopes)) {
|
||||||
|
Set<String> appScopes = OauthUtil.convertStrToList(clientScopes);
|
||||||
|
for (String scope : scopes) {
|
||||||
|
if (!appScopes.contains(scope)) {
|
||||||
|
throw new InvalidScopeException("Invalid scope: " + scope + ". " + clientScopes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the current grant type supports redirect uri
|
||||||
|
*
|
||||||
|
* @param grantTypes some grant types
|
||||||
|
* @return true if the supplied grant types includes one or more of the redirect types
|
||||||
|
*/
|
||||||
|
private static boolean containsRedirectGrantType(Set<String> grantTypes) {
|
||||||
|
for (String type : grantTypes) {
|
||||||
|
if (REDIRECT_GRANT_TYPES.contains(type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the callback url
|
||||||
|
*
|
||||||
|
* @param requestRedirectUri The callback url passed in the current request
|
||||||
|
* @param clientDetail client detail
|
||||||
|
*/
|
||||||
|
public static void validateRedirectUri(String requestRedirectUri, ClientDetail clientDetail) {
|
||||||
|
String clientGrantTypes = clientDetail.getGrantTypes();
|
||||||
|
Set<String> clientGrantTypeSet = OauthUtil.convertStrToList(clientGrantTypes);
|
||||||
|
if (clientGrantTypeSet.isEmpty()) {
|
||||||
|
throw new InvalidGrantException("A client must have at least one authorized grant type.");
|
||||||
|
}
|
||||||
|
if (!containsRedirectGrantType(clientGrantTypeSet)) {
|
||||||
|
throw new InvalidGrantException(
|
||||||
|
"A redirect_uri can only be used by implicit or authorization_code grant types.");
|
||||||
|
}
|
||||||
|
String clientRedirectUri = clientDetail.getRedirectUri();
|
||||||
|
if (requestRedirectUri == null || !requestRedirectUri.equals(clientRedirectUri)) {
|
||||||
|
throw new InvalidRedirectUriException(ErrorResponse.INVALID_REDIRECT_URI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Only the authorization code mode will verify pkce, and the client secret will be verified when pkce is not enabled
|
||||||
|
* <p>
|
||||||
|
* 2. Implicit authorization grant and password authorization grant do not need to verify client secret
|
||||||
|
* <p>
|
||||||
|
* 3. Client authorizatio grantn needs to verify the client secret
|
||||||
|
*
|
||||||
|
* @param param request params
|
||||||
|
* @param clientDetail client detail
|
||||||
|
* @param oauth2Service oauth2Service
|
||||||
|
*/
|
||||||
|
public static void validateSecret(IdsRequestParam param, ClientDetail clientDetail, Oauth2Service oauth2Service) {
|
||||||
|
if (param.getGrantType().equals(GrantType.AUTHORIZATION_CODE.getType())) {
|
||||||
|
if (param.isEnablePkce()) {
|
||||||
|
oauth2Service.validateAuthrizationCodeChallenge(param.getCodeVerifier(), param.getCode());
|
||||||
|
} else {
|
||||||
|
if (!clientDetail.getClientSecret().equals(param.getClientSecret())) {
|
||||||
|
throw new InvalidClientException(ErrorResponse.INVALID_CLIENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!clientDetail.getClientSecret().equals(param.getClientSecret())) {
|
||||||
|
throw new InvalidClientException(ErrorResponse.INVALID_CLIENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the response type
|
||||||
|
*
|
||||||
|
* @param requestResponseType The response type in the current request
|
||||||
|
* @param clientResponseTypes Response type in client detail
|
||||||
|
*/
|
||||||
|
public static void validateResponseType(String requestResponseType, String clientResponseTypes) {
|
||||||
|
Set<String> clientResponseTypeSet = OauthUtil.convertStrToList(clientResponseTypes);
|
||||||
|
if (!StringUtil.isEmpty(clientResponseTypes) && !clientResponseTypeSet.contains(requestResponseType)) {
|
||||||
|
throw new UnsupportedResponseTypeException(ErrorResponse.UNSUPPORTED_RESPONSE_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the grant type
|
||||||
|
*
|
||||||
|
* @param requestGrantType The grant type in the current request
|
||||||
|
* @param clientGrantTypes Grant type in client detail
|
||||||
|
* @param equalTo {@code requestGrantType} Must match grant type value
|
||||||
|
*/
|
||||||
|
public static void validateGrantType(String requestGrantType, String clientGrantTypes, GrantType equalTo) {
|
||||||
|
Set<String> grantTypeSet = OauthUtil.convertStrToList(clientGrantTypes);
|
||||||
|
if (StringUtil.isEmpty(requestGrantType) || ArrayUtil.isEmpty(grantTypeSet) || !grantTypeSet.contains(requestGrantType)) {
|
||||||
|
throw new UnsupportedGrantTypeException(ErrorResponse.UNSUPPORTED_GRANT_TYPE);
|
||||||
|
}
|
||||||
|
if (null != equalTo && !requestGrantType.equals(equalTo.getType())) {
|
||||||
|
throw new UnsupportedGrantTypeException(ErrorResponse.UNSUPPORTED_GRANT_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void validClientDetail(ClientDetail clientDetail) {
|
||||||
|
if (clientDetail == null) {
|
||||||
|
throw new InvalidClientException(ErrorResponse.INVALID_CLIENT);
|
||||||
|
}
|
||||||
|
if (!Optional.ofNullable(clientDetail.getAvailable()).orElse(false)) {
|
||||||
|
throw new InvalidClientException(ErrorResponse.DISABLED_CLIENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the expiration time of access token, default is {@link IdsConsts#ACCESS_TOKEN_ACTIVITY_TIME}
|
||||||
|
*
|
||||||
|
* @param expiresIn The expiration time of the access token in the client detail
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
public static long getAccessTokenExpiresIn(Long expiresIn) {
|
||||||
|
return Optional.ofNullable(expiresIn).orElse(IdsConsts.ACCESS_TOKEN_ACTIVITY_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the expiration time of refresh token, the default is {@link IdsConsts#REFRESH_TOKEN_ACTIVITY_TIME}
|
||||||
|
*
|
||||||
|
* @param expiresIn The expiration time of the refresh token in the client detail
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
public static long getRefreshTokenExpiresIn(Long expiresIn) {
|
||||||
|
return Optional.ofNullable(expiresIn).orElse(IdsConsts.REFRESH_TOKEN_ACTIVITY_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the expiration time of the authorization code code, the default is {@link IdsConsts#AUTHORIZATION_CODE_ACTIVITY_TIME}
|
||||||
|
*
|
||||||
|
* @param expiresIn The expiration time of the code in the client detail
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
public static long getCodeExpiresIn(Long expiresIn) {
|
||||||
|
return Optional.ofNullable(expiresIn).orElse(IdsConsts.AUTHORIZATION_CODE_ACTIVITY_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the expiration time of id token, the default is{@link IdsConsts#ID_TOKEN_ACTIVITY_TIME}
|
||||||
|
*
|
||||||
|
* @param expiresIn The expiration time of the id token in the client detail
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
public static long getIdTokenExpiresIn(Long expiresIn) {
|
||||||
|
return Optional.ofNullable(expiresIn).orElse(IdsConsts.ID_TOKEN_ACTIVITY_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the expiration deadline of access token
|
||||||
|
*
|
||||||
|
* @param expiresIn The expiration time of the access token in the client detail
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
public static LocalDateTime getAccessTokenExpiresAt(Long expiresIn) {
|
||||||
|
expiresIn = getAccessTokenExpiresIn(expiresIn);
|
||||||
|
return DateUtil.ofEpochSecond(System.currentTimeMillis() + expiresIn * 1000, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the expiration deadline of refresh token
|
||||||
|
*
|
||||||
|
* @param expiresIn The expiration time of the refresh token in the client detail
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
public static LocalDateTime getRefreshTokenExpiresAt(Long expiresIn) {
|
||||||
|
expiresIn = getRefreshTokenExpiresIn(expiresIn);
|
||||||
|
return DateUtil.ofEpochSecond(System.currentTimeMillis() + expiresIn * 1000, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the expiration deadline of authorization code
|
||||||
|
*
|
||||||
|
* @param expiresIn The expiration time of the code in the client detail
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
public static LocalDateTime getCodeExpiresAt(Long expiresIn) {
|
||||||
|
expiresIn = getCodeExpiresIn(expiresIn);
|
||||||
|
return DateUtil.ofEpochSecond(System.currentTimeMillis() + expiresIn * 1000, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the expiration deadline of id token
|
||||||
|
*
|
||||||
|
* @param expiresIn The expiration time of the id token in the client detail
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
public static LocalDateTime getIdTokenExpiresAt(Long expiresIn) {
|
||||||
|
expiresIn = getIdTokenExpiresIn(expiresIn);
|
||||||
|
return DateUtil.ofEpochSecond(System.currentTimeMillis() + expiresIn * 1000, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create authorize url
|
||||||
|
*
|
||||||
|
* @param authorizeUrl authorize url
|
||||||
|
* @param param request params
|
||||||
|
* @return authorizeUrl
|
||||||
|
*/
|
||||||
|
public static String createAuthorizeUrl(String authorizeUrl, IdsRequestParam param) {
|
||||||
|
Map<String, Object> model = new HashMap<>(13);
|
||||||
|
model.put("client_id", param.getClientId());
|
||||||
|
|
||||||
|
if (StringUtil.isNotEmpty(param.getRedirectUri())) {
|
||||||
|
model.put("redirect_uri", param.getRedirectUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtil.isNotEmpty(param.getScope())) {
|
||||||
|
model.put("scope", param.getScope());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtil.isNotEmpty(param.getState())) {
|
||||||
|
model.put("state", param.getState());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtil.isNotEmpty(param.getNonce())) {
|
||||||
|
model.put("nonce", param.getNonce());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtil.isNotEmpty(param.getResponseType())) {
|
||||||
|
model.put("response_type", param.getResponseType());
|
||||||
|
}
|
||||||
|
if (StringUtil.isNotEmpty(param.getCodeChallengeMethod()) || StringUtil.isNotEmpty(param.getCodeChallenge())) {
|
||||||
|
model.put("code_challenge_method", param.getCodeChallengeMethod());
|
||||||
|
model.put("code_challenge", param.getCodeChallenge());
|
||||||
|
}
|
||||||
|
if (StringUtil.isNotEmpty(param.getAutoapprove())) {
|
||||||
|
model.put("autoapprove", param.getAutoapprove());
|
||||||
|
}
|
||||||
|
String uriParams = URLUtil.buildQuery(model, StandardCharsets.UTF_8);
|
||||||
|
if (authorizeUrl.contains("?")) {
|
||||||
|
authorizeUrl = authorizeUrl + (authorizeUrl.endsWith("?") ? "" : "&") + uriParams;
|
||||||
|
} else {
|
||||||
|
authorizeUrl = authorizeUrl + "?" + uriParams;
|
||||||
|
}
|
||||||
|
return authorizeUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String generateClientId() {
|
||||||
|
return RandomUtil.randomString(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String generateClientSecret() {
|
||||||
|
return RandomUtil.randomString(40);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isOidcProtocol(String scopes) {
|
||||||
|
Set<String> scopeList = OauthUtil.convertStrToList(scopes);
|
||||||
|
return scopeList.contains("openid");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suitable for oauth 2.0 pkce enhanced protocol
|
||||||
|
*
|
||||||
|
* @param codeChallengeMethod s256 / plain
|
||||||
|
* @param codeVerifier code verifier, Generated by the developer
|
||||||
|
* @return code challenge
|
||||||
|
*/
|
||||||
|
public static String generateCodeChallenge(String codeChallengeMethod, String codeVerifier) {
|
||||||
|
if ("S256".equalsIgnoreCase(codeChallengeMethod)) {
|
||||||
|
// https://tools.ietf.org/html/rfc7636#section-4.2
|
||||||
|
// code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
|
||||||
|
return Base64.encodeUrlSafe(SecureUtil.sha256().digest(codeVerifier));
|
||||||
|
} else {
|
||||||
|
return codeVerifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.URLUtil;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class ObjectUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the {@code str} does not end in {@code suffix}, then {@code suffix} is appended after {@code str};
|
||||||
|
* If {@code suffix} is already included, return directly to {@code str}
|
||||||
|
*
|
||||||
|
* @param str str
|
||||||
|
* @param suffix Content to be added
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String appendIfNotEndWith(String str, String suffix) {
|
||||||
|
if (StringUtil.isEmpty(str) || StringUtil.isEmpty(suffix)) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
return str.endsWith(suffix) ? str : str + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map to string, the format of the converted string is {@code xxx=xxx&xxx=xxx}
|
||||||
|
*
|
||||||
|
* @param params Map to be converted
|
||||||
|
* @param encode Whether to encode the value of the map
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String parseMapToString(Map<String, String> params, boolean encode) {
|
||||||
|
if (null == params || params.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
List<String> paramList = new ArrayList<>();
|
||||||
|
params.forEach((k, v) -> {
|
||||||
|
if (null == v) {
|
||||||
|
paramList.add(k + "=");
|
||||||
|
} else {
|
||||||
|
paramList.add(k + "=" + (encode ? URLUtil.encode(v) : v));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return String.join("&", paramList);
|
||||||
|
}
|
||||||
|
}
|
218
jap-ids/src/main/java/com/fujieid/jap/ids/util/TokenUtil.java
Normal file
218
jap-ids/src/main/java/com/fujieid/jap/ids/util/TokenUtil.java
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import com.fujieid.jap.core.util.RequestUtil;
|
||||||
|
import com.fujieid.jap.ids.JapIds;
|
||||||
|
import com.fujieid.jap.ids.exception.InvalidTokenException;
|
||||||
|
import com.fujieid.jap.ids.model.AccessToken;
|
||||||
|
import com.fujieid.jap.ids.model.ClientDetail;
|
||||||
|
import com.fujieid.jap.ids.model.IdsConsts;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
import com.fujieid.jap.ids.model.enums.ErrorResponse;
|
||||||
|
import com.fujieid.jap.ids.model.enums.TokenAuthMethod;
|
||||||
|
import com.xkcoding.json.util.StringUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public class TokenUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get access token from request
|
||||||
|
*
|
||||||
|
* @param request request
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String getAccessToken(HttpServletRequest request) {
|
||||||
|
List<TokenAuthMethod> tokenAuthMethods = JapIds.getIdsConfig().getTokenAuthMethods();
|
||||||
|
if (ObjectUtil.isEmpty(tokenAuthMethods)) {
|
||||||
|
tokenAuthMethods = Collections.singletonList(TokenAuthMethod.ALL);
|
||||||
|
}
|
||||||
|
if (tokenAuthMethods.contains(TokenAuthMethod.ALL)) {
|
||||||
|
String accessToken = getAccessTokenFromUrl(request);
|
||||||
|
if (StringUtil.isEmpty(accessToken)) {
|
||||||
|
accessToken = getAccessTokenFromHeader(request);
|
||||||
|
if (StringUtil.isEmpty(accessToken)) {
|
||||||
|
accessToken = getAccessTokenFromCookie(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accessToken;
|
||||||
|
} else {
|
||||||
|
if (tokenAuthMethods.contains(TokenAuthMethod.TOKEN_URL)) {
|
||||||
|
String accessToken = getAccessTokenFromUrl(request);
|
||||||
|
if (accessToken != null) {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tokenAuthMethods.contains(TokenAuthMethod.TOKEN_HEADER)) {
|
||||||
|
String accessToken = getAccessTokenFromHeader(request);
|
||||||
|
if (accessToken != null) {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tokenAuthMethods.contains(TokenAuthMethod.TOKEN_COOKIE)) {
|
||||||
|
return getAccessTokenFromCookie(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getAccessTokenFromUrl(HttpServletRequest request) {
|
||||||
|
String accessToken = RequestUtil.getParam(IdsConsts.ACCESS_TOKEN, request);
|
||||||
|
if (StringUtil.isNotEmpty(accessToken)) {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getAccessTokenFromHeader(HttpServletRequest request) {
|
||||||
|
String accessToken = RequestUtil.getHeader(IdsConsts.AUTHORIZATION_HEADER_NAME, request);
|
||||||
|
return BearerToken.parse(accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getAccessTokenFromCookie(HttpServletRequest request) {
|
||||||
|
return RequestUtil.getCookieVal(request, IdsConsts.ACCESS_TOKEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createIdToken(ClientDetail clientDetail, UserInfo user, String nonce) {
|
||||||
|
long idTokenExpiresIn = OauthUtil.getIdTokenExpiresIn(clientDetail.getIdTokenExpiresIn());
|
||||||
|
return JwtUtil.createJwtToken(clientDetail.getClientId(), user, idTokenExpiresIn, nonce, JapIds.getIdsConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AccessToken createAccessToken(UserInfo user, ClientDetail clientDetail, String grantType, String scope, String nonce) {
|
||||||
|
String clientId = clientDetail.getClientId();
|
||||||
|
|
||||||
|
long accessTokenExpiresIn = OauthUtil.getAccessTokenExpiresIn(clientDetail.getAccessTokenExpiresIn());
|
||||||
|
long refreshTokenExpiresIn = OauthUtil.getAccessTokenExpiresIn(clientDetail.getRefreshTokenExpiresIn());
|
||||||
|
|
||||||
|
String accessTokenStr = JwtUtil.createJwtToken(clientId, user, accessTokenExpiresIn, nonce, JapIds.getIdsConfig());
|
||||||
|
String refreshTokenStr = SecureUtil.sha256(clientId.concat(scope).concat(System.currentTimeMillis() + ""));
|
||||||
|
|
||||||
|
AccessToken accessToken = new AccessToken();
|
||||||
|
accessToken.setAccessToken(accessTokenStr);
|
||||||
|
accessToken.setRefreshToken(refreshTokenStr);
|
||||||
|
accessToken.setGrantType(grantType);
|
||||||
|
if (null != user) {
|
||||||
|
accessToken.setUserName(user.getUsername());
|
||||||
|
accessToken.setUserId(user.getId());
|
||||||
|
}
|
||||||
|
accessToken.setClientId(clientId);
|
||||||
|
accessToken.setScope(scope);
|
||||||
|
|
||||||
|
accessToken.setRefreshTokenExpiresIn(refreshTokenExpiresIn);
|
||||||
|
accessToken.setAccessTokenExpiresIn(accessTokenExpiresIn);
|
||||||
|
|
||||||
|
accessToken.setAccessTokenExpiration(OauthUtil.getAccessTokenExpiresAt(accessTokenExpiresIn));
|
||||||
|
accessToken.setRefreshTokenExpiration(OauthUtil.getRefreshTokenExpiresAt(refreshTokenExpiresIn));
|
||||||
|
|
||||||
|
String token = IdsConsts.OAUTH_ACCESS_TOKEN_CACHE_KEY + accessTokenStr;
|
||||||
|
String rtoken = IdsConsts.OAUTH_REFRESH_TOKEN_CACHE_KEY + refreshTokenStr;
|
||||||
|
JapIds.getContext().getCache().set(token, accessToken, accessTokenExpiresIn * 1000);
|
||||||
|
JapIds.getContext().getCache().set(rtoken, accessToken, refreshTokenExpiresIn * 1000);
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AccessToken refreshAccessToken(UserInfo user, ClientDetail clientDetail, AccessToken accessToken, String nonce) {
|
||||||
|
String rawToken = accessToken.getAccessToken();
|
||||||
|
String accessTokenStr = JwtUtil.createJwtToken(clientDetail.getClientId(), user, clientDetail.getAccessTokenExpiresIn(), nonce, JapIds.getIdsConfig());
|
||||||
|
accessToken.setAccessToken(accessTokenStr);
|
||||||
|
accessToken.setAccessTokenExpiresIn(clientDetail.getAccessTokenExpiresIn());
|
||||||
|
|
||||||
|
accessToken.setAccessTokenExpiration(OauthUtil.getAccessTokenExpiresAt(clientDetail.getAccessTokenExpiresIn()));
|
||||||
|
|
||||||
|
String tokenCacheKey = IdsConsts.OAUTH_ACCESS_TOKEN_CACHE_KEY + accessTokenStr;
|
||||||
|
JapIds.getContext().getCache().set(tokenCacheKey, accessTokenStr, clientDetail.getAccessTokenExpiresIn() * 1000);
|
||||||
|
|
||||||
|
String rawTokenCacheKey = IdsConsts.OAUTH_ACCESS_TOKEN_CACHE_KEY + rawToken;
|
||||||
|
JapIds.getContext().getCache().removeKey(rawTokenCacheKey);
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AccessToken createClientCredentialsAccessToken(ClientDetail clientDetail, String grantType, String scope, String nonce) {
|
||||||
|
return createAccessToken(null, clientDetail, grantType, scope, nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void invalidateToken(HttpServletRequest request) {
|
||||||
|
String accessTokenStr = TokenUtil.getAccessToken(request);
|
||||||
|
AccessToken accessToken = TokenUtil.getByAccessToken(accessTokenStr);
|
||||||
|
if (null != accessToken) {
|
||||||
|
String token = IdsConsts.OAUTH_ACCESS_TOKEN_CACHE_KEY + accessTokenStr;
|
||||||
|
String rtoken = IdsConsts.OAUTH_REFRESH_TOKEN_CACHE_KEY + accessToken.getRefreshToken();
|
||||||
|
JapIds.getContext().getCache().removeKey(token);
|
||||||
|
JapIds.getContext().getCache().removeKey(rtoken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void validateAccessToken(String accessToken) {
|
||||||
|
|
||||||
|
AccessToken token = getByAccessToken(accessToken);
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
throw new InvalidTokenException(ErrorResponse.INVALID_TOKEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDateTime nowDateTime = DateUtil.nowDate();
|
||||||
|
|
||||||
|
if (token.getAccessTokenExpiration().isBefore(nowDateTime)) {
|
||||||
|
throw new InvalidTokenException(ErrorResponse.EXPIRED_TOKEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void validateRefreshToken(String refreshToken) {
|
||||||
|
|
||||||
|
AccessToken token = getByRefreshToken(refreshToken);
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
throw new InvalidTokenException(ErrorResponse.INVALID_TOKEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDateTime nowDateTime = DateUtil.nowDate();
|
||||||
|
|
||||||
|
if (token.getRefreshTokenExpiration().isBefore(nowDateTime)) {
|
||||||
|
throw new InvalidTokenException(ErrorResponse.EXPIRED_TOKEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AccessToken getByAccessToken(String accessToken) {
|
||||||
|
if (null == accessToken) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
accessToken = BearerToken.parse(accessToken);
|
||||||
|
String token = IdsConsts.OAUTH_ACCESS_TOKEN_CACHE_KEY + accessToken;
|
||||||
|
return (AccessToken) JapIds.getContext().getCache().get(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AccessToken getByRefreshToken(String refreshToken) {
|
||||||
|
if (null == refreshToken) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String token = IdsConsts.OAUTH_REFRESH_TOKEN_CACHE_KEY + refreshToken;
|
||||||
|
return (AccessToken) JapIds.getContext().getCache().get(token);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Tools of ids
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
package com.fujieid.jap.ids.util;
|
286
jap-ids/src/test/java/com/fujieid/jap/ids/util/JwtUtilTest.java
Normal file
286
jap-ids/src/test/java/com/fujieid/jap/ids/util/JwtUtilTest.java
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2040, 北京符节科技有限公司 (support@fujieid.com & https://www.fujieid.com).
|
||||||
|
* <p>
|
||||||
|
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* <p>
|
||||||
|
* http://www.gnu.org/licenses/lgpl.html
|
||||||
|
* <p>
|
||||||
|
* 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 com.fujieid.jap.ids.util;
|
||||||
|
|
||||||
|
import com.fujieid.jap.ids.config.IdsConfig;
|
||||||
|
import com.fujieid.jap.ids.config.JwtConfig;
|
||||||
|
import com.fujieid.jap.ids.model.UserInfo;
|
||||||
|
import com.fujieid.jap.ids.model.enums.JwtVerificationType;
|
||||||
|
import com.fujieid.jap.ids.model.enums.TokenSigningAlg;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://mkjwk.org/
|
||||||
|
*/
|
||||||
|
public class JwtUtilTest {
|
||||||
|
|
||||||
|
String clientId = "xxxxxxx";
|
||||||
|
UserInfo userInfo = new UserInfo();
|
||||||
|
String nonce = "asdasd";
|
||||||
|
|
||||||
|
String issuer = "http://www.baidu.com";
|
||||||
|
Long tokenExpireIn = 365 * 24 * 60 * 60L;
|
||||||
|
String rs256JwksJson = "{\n" +
|
||||||
|
" \"keys\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"p\": \"v5G0QPkr9zi1znff2g7p5K1ac1F2KNjXmk31Etl0UrRBwHiTxM_MkkldGlxnXWoFL4_cPZZMt_W14Td5qApknLFOh9iRWRPwqlFgC-eQzUjPeYvxjRbtV5QUHtbzrDCLjLiSNyhsLXHyi_yOawD2BS4U6sBWMSJlL2lShU7EAaU\",\n" +
|
||||||
|
" \"kty\": \"RSA\",\n" +
|
||||||
|
" \"q\": \"s2X9UeuEWky_io9hFAoHZjBxMBheNAGrHXtWat6zlg2tf_SIKpZ7Xs8C_-kr9Pvj-D428QsOjFZE-EtNBSXoMrvlMk7fGDl9x1dHvLS9GSitkXH2-Wthg8j0j0nfAmyEt94jP-XEkYic1Ok7EfBOPuvL21HO7YuB-cOff9ZGvBk\",\n" +
|
||||||
|
" \"d\": \"Rj-QBeBdx85VIHkwVY1T94ZeeC_Z6Zw-cz5lk5Msw0U9QhSTWo28-d2lYjK7dhQn-E19JhTbCVE11UuUqENKZmO__yRgO1UJaj2x6vWMtgJptah7m8lI-QW0w6TnVxAHWfRPpKSEfbN4SpeufYf5PYhmmzT0A954Z2o0kqS4iHd0gwNAovOXaxriGXO1CcOQjBFEcm0BdboQZ7CKCoJ1D6S0xZpVFSJg-1AtagY5dzStyekzETO2tQSmVw4ogIoJsIbu3aYwbukmCoULQfJ36D0mPzrTG5oocEbbuCps_vH72VjZORHHAl4hwritFT_jD2bdQHSNMGukga8C0L1WQQ\",\n" +
|
||||||
|
" \"e\": \"AQAB\",\n" +
|
||||||
|
" \"use\": \"sig\",\n" +
|
||||||
|
" \"kid\": \"jap-jwk-keyid\",\n" +
|
||||||
|
" \"qi\": \"Asr5dZMDvwgquE6uFnDaBC76PY5JUzxQ5wY5oc4nhIm8UxQWwYZTWq-HOWkMB5c99fG1QxLWQKGtsguXfOXoNgnI--yHzLZcXf1XAd0siguaF1cgQIqwRUf4byofE6uJ-2ZON_ezn6Uvly8fDIlgwmKAiiwWvHI4iLqvqOReBgs\",\n" +
|
||||||
|
" \"dp\": \"oIUzuFnR6FcBqJ8z2KE0haRorUZuLy38A1UdbQz_dqmKiv--OmUw8sc8l3EkP9ctvzvZfVWqtV7TZ4M3koIa6l18A0KKEE0wFVcYlwETiaBgEWYdIm86s27mKS1Og1MuK90gz800UCQx6_DVWX41qAOEDWzbDFLY3JBxUDi-7u0\",\n" +
|
||||||
|
" \"alg\": \"RS256\",\n" +
|
||||||
|
" \"dq\": \"MpNSM0IecgapCTsatzeMlnaZsmFsTWUbBJi86CwYnPkGLMiXisoZxcS-p77osYxB3L5NZu8jDtVTZFx2PjlNmN_34ZLyujWbDBPDGaQqm2koZZSnd_GZ8Dk7GRpOULSfRebOMTlpjU3iSPPnv0rsBDkdo5sQp09pOSy5TqTuFCE\",\n" +
|
||||||
|
" \"n\": \"hj8zFdhYFi-47PO4B4HTRuOLPR_rpZJi66g4JoY4gyhb5v3Q57etSU9BnW9QQNoUMDvhCFSwkz0hgY5HqVj0zOG5s9x2a594UDIinKsm434b-pT6bueYdvM_mIUEKka5pqhy90wTTka42GvM-rBATHPTarq0kPTR1iBtYao8zX-RWmCbdumEWOkMFUGbBkUcOSJWzoLzN161WdYr2kJU5PFraUP3hG9fPpMEtvqd6IwEL-MOVx3nqc7zk3D91E6eU7EaOy8nz8echQLl6Ps34BSwEpgOhaHDD6IJzetW-KorYeC0r0okXhrl0sUVE2c71vKPVVtueJSIH6OwA3dVHQ\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
"}";
|
||||||
|
String rs384JwksJson = "{\n" +
|
||||||
|
" \"keys\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"p\": \"83Ql5zOr0s0xxfoXHs77rd5vwG2_gwudv_jwF-gCOeuA8LOsCyBPFMoqr5JG8ebvLvtDCbThUj7xuZ49fGFD6KCHXMlt9NRtJKguzVn7wuiVjyF1VD0W_Dk4Ay_0X6hpTa39sRM7U3mxt5PgCYOOsKd6QsexNUdqawnE6fRivxM\",\n" +
|
||||||
|
" \"kty\": \"RSA\",\n" +
|
||||||
|
" \"q\": \"w2z94Lo3ai1JnTf9jLynEy65zclB9zvAmTm7r6HMfak0oWgPrM_jfiLo-lO8eSd3CdQGaEcGucKoM8fYNLxq6cBisNcm02sk7KAfkjsIzW7JLRbT3ORjG20-fzyG0q0UbijYbEZnkX4D-3AwR-myvPiT1ywYaMUdWel3ZC2nFR8\",\n" +
|
||||||
|
" \"d\": \"uQGDQOPwYn4_vqLc5nnNyJxPdbltnpM6zAqg65K2k7E9gT7_9u8v1y-GYvrQsELgVcAxGVmURPQctjyqigiSkUvw-_4U4AY3_ZLAqUZ-CFhzkoZhhsnXlZJHjvWWtZqEUsWVzALYK8GiSfcdOpKBNeHiCIgw3d4fcCmGZUlDSAhVPT2CJosGhSIP7K2B9y9ythgDQ_R67FhrtFTZQWml9XkxXFXekhHsNtXVjIXRRmZeKcPfn94-eOnIhApVaVHgFJcJGH94Xbbh-nqs5xy4ObOm8NdGf8-ufDN2zcmr2sLdyhewdEi80JK1DGPP5gQhZfxshonX7GE3Fx5o0hovoQ\",\n" +
|
||||||
|
" \"e\": \"AQAB\",\n" +
|
||||||
|
" \"use\": \"sig\",\n" +
|
||||||
|
" \"kid\": \"jap-jwk-keyid\",\n" +
|
||||||
|
" \"qi\": \"fMFk60XjrRKxro17rI5MOtgvriNu4BDARSxOQ8c4eDRoM6Wy4g6vUwi6Bj7qM39id8z1sfUnryFJyVzxuSSzLlgawwaLM_LGwep4AkToz0l9Mmm1avl0p_oQl05ywSo0SquGatdiwHaHa80bDyzsA3ebI31w2Rrmjr81nDiUz9k\",\n" +
|
||||||
|
" \"dp\": \"PaZoAshe9p7nv865FCAuM7Vkb0JbgP_sDrUnd6ZVCf3NRSb6pkakQAuCC7vrI07ruuX97_NSK9WsuOiNgXXQEJS2MpT_t0Qj72h3kaD71Du5w-khIRfnPi_vMz9tjtvC7tzkpXbNSzJCAs77qO0bsTh4CXkwMuHG3Rw4NVahuuk\",\n" +
|
||||||
|
" \"alg\": \"RS384\",\n" +
|
||||||
|
" \"dq\": \"MsOdL0MwIeShurVQp75ZqCH7IfmlqRNcdHEK0BS3iezqPwNJDxrxfVKUMnKOAuq9gVASWgQZOyfViZ3gC9Ll8tKG0GkTLNgoP09Y5CNxpeuhVpUXc8nf9L_r_CE85H0RUYxKq9WeEa0qW6ZI5GVQiMYJoVtS--Q4O6Lp4Jv7SwE\",\n" +
|
||||||
|
" \"n\": \"udkfTpoTbOSKfQMnLqSinnFLENRY3sJqKgYD6rsKanLmDHrvWrACSQPJ9ANXiEklK5ryAVxASNygxDxGeC4R3ofPT6MlgXjLr01vxUM9DW4DHpVQsnm7H8aaxC_9J-ddcVTyylKTqVWZBIai3gBsRZOKgpExRwkf2x5RnS1lDiWtvCO_R_CJawYYopw26XiqSGC_Y9UNysGcBK8pCMx0VhROexEtqD_gl6Lr7LaH9AdftGRihcVSMeoLdqu4CVaVwUiYoNWkGvb9qv0hBnlevG94NiTui5Lyr5sHp8g9DlIqAy7ehPYuXeNdcDY5i3hkl7pLkBy8nhk4mUnNrgayTQ\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
"}";
|
||||||
|
String rs512JwksJson = "{\n" +
|
||||||
|
" \"keys\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"p\": \"8sGhs7HKVhhMbR_SgLWncF5rqmbyDE4vNit-rugcCExJJo5ZvGzxHJ_UQfJvDEB1V90hr2loUhmqkWNd3WLtmr89_yoenlt2MN1lDX_lFL01uEmzmjcDhdL5GgxWg-FykJeR0Os_qJd4rpcODVKQjO_VQxNQwaTAhs__hHn2QdM\",\n" +
|
||||||
|
" \"kty\": \"RSA\",\n" +
|
||||||
|
" \"q\": \"qpaibUW1G35-gXniwAoNJMa2-b_LiOMBk4_DCmEIE8m4hRy3hTvXgbqtrMv7Xbd0BR_tQujciwovDaQE9ltOnN3zlKqe9v5xqGpsRTWQ_jLUN-Pq-Ae9BAb3BmA_sJnnojVp_DkfLSI_0VIyIIrjlPnvnrVtBCuiMdQNgGd0HqE\",\n" +
|
||||||
|
" \"d\": \"c0VcVI7VfRFmdCBkeEmuNGV301cjqlDH4w3cbRQPCHh31kjFeRCbrUtLYGO4m9YBKGMEReu1Uvjz4p3orR0wDanFgqtRVis6dpZD0xIhdGU5emOpAY5K05nNOS7MNEBntoO41jLpHo3-0pGqBMyYnOFFpZ0Jgoq_n9X_cGsBZvcnjEoNM_YnnshoVVNbCrfcxa5UWwuIstl6sSm0PDxtXon-Ydv2MAxTA5ujZy1agCcjjcxXw8thpP6ZJk_graeY0KHIAydNp-6xg0xosnHbydLCA6Iiz1qlRoPr9Oo5KB-RQdWdJFRFFPteEt8pcHKtJZ_ytCe4vYBs0EeC1sLuQQ\",\n" +
|
||||||
|
" \"e\": \"AQAB\",\n" +
|
||||||
|
" \"use\": \"sig\",\n" +
|
||||||
|
" \"kid\": \"jap-jwk-keyid\",\n" +
|
||||||
|
" \"qi\": \"pCxLgf9KQiNeo8cw3BmX0s9RWaMPL9kaJcE-4kwbIzKSO1oLNd-4a43WnyFb5P7VLnbnR9AXu__DpMVKQKWL5SPkevmNGVf97pc36YkaKh379lF_tpDRgyt9Z0bpykIu_rsTi3bemIvPzcTM6Bgg7flo16k62SOFH9pc5sTurrU\",\n" +
|
||||||
|
" \"dp\": \"AvxKptEa8fAekIEBr7-MLZ-bp17Yvzn-7qWeSzxji96UT7sUc3LLjFSS4bS_lOD-EHSRw3yCYfAa3urf7qcW0P5lHsw_0CbDz1oJsh7OjHC_RmLxqIXgrzanBaD9N2YAaLLUgkNCZyplu4_0BknrqTAR6V9FcPw7uey48cImOy0\",\n" +
|
||||||
|
" \"alg\": \"RS512\",\n" +
|
||||||
|
" \"dq\": \"kUBgH4EaW8XSe_bHv1MPq__T70aDTRRV1Eq1_VFvqkG57wXrsfOpZZoJpbeuWjcKAA8WXEGhAHb0Z74AR7CpeGJ4tF6vqoovRwMPG8MnqXqoPsq_2N_l7tbrYa90q6_wjqrCivQseqbOBjLh4dnBPKmwgcfjgoiQu7LeqDXupuE\",\n" +
|
||||||
|
" \"n\": \"ocNs3Do6B0506SP6w2POw5LZmCNtmm1IrkLiduDewapB2Z7fziDLpNhPkgK2ouAFFAO7LVmPoRd4xojO1FZxCXR2-hFggI86lOtaTptoln9v-6_J6dbVrOPjk9BLiEiOKr44xJJbbnesMvt4SX2kc_sUkQ9cP7hxa1AT8dOpxeR_riw_bx2VGsDc4dWTLsqIsCxZdyllJE9CFz3UFz60ZPByW0Ai1fuhpc1RFYuxA4Z422Z5xNvev4wwEXNX52Sofnuqebl1y2DdYuLCogxUAOMT4e3fJ-KRFSFZaSwx9lDe5npqxeKNC5TDzv0_4ZZkCOwHSO7IqmugDzEtSDIfsw\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
"}";
|
||||||
|
String es256JwksJson = "{\n" +
|
||||||
|
" \"keys\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"kty\": \"EC\",\n" +
|
||||||
|
" \"d\": \"G0bXBYlLfzC2fIjR2Rh8YUP1BeyS37oSOTgoFNp6hDU\",\n" +
|
||||||
|
" \"use\": \"sig\",\n" +
|
||||||
|
" \"crv\": \"P-256\",\n" +
|
||||||
|
" \"kid\": \"jap-jwk-keyid\",\n" +
|
||||||
|
" \"x\": \"gaNg_BBeCHwcbvmI94F9qDwh-EloVd0GOZMDJ03hlnk\",\n" +
|
||||||
|
" \"y\": \"65NEHBW8cwIEQ1IK8x8uskaRakujNoNoC_T2KjOSVfY\",\n" +
|
||||||
|
" \"alg\": \"ES256\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
"}";
|
||||||
|
String es384JwksJson = "{\n" +
|
||||||
|
" \"keys\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"kty\": \"EC\",\n" +
|
||||||
|
" \"d\": \"N_5ZUo-CE-H_zkvTV4w3hrS5QLBf2i9gyGLVUQCTY-8jsY0nJoyy3VQ2Pz2DRXW1\",\n" +
|
||||||
|
" \"use\": \"sig\",\n" +
|
||||||
|
" \"crv\": \"P-384\",\n" +
|
||||||
|
" \"kid\": \"jap-jwk-keyid\",\n" +
|
||||||
|
" \"x\": \"9u6MR_5wSQIqi84EeZcO5BuHfnpDUgnz-GvFRrU3fe66Z_n6hbEERClb1UhcdVZf\",\n" +
|
||||||
|
" \"y\": \"aRrJIGToPMeDgboLGUgYa0kvx7KyjlxM8WskEg_eteipXWR-natHIjFwFFSqDb9A\",\n" +
|
||||||
|
" \"alg\": \"ES384\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
"}";
|
||||||
|
String es512JwksJson = "{\n" +
|
||||||
|
" \"keys\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"kty\": \"EC\",\n" +
|
||||||
|
" \"d\": \"AHWjfpnoFxayAdKwLse6dsOXDU0mUP5ZnnpyCTWFiqR8QbvCtosRv01hds4yjnLLoqQQ2EU3vsBo9GLc2Z94q5l3\",\n" +
|
||||||
|
" \"use\": \"sig\",\n" +
|
||||||
|
" \"crv\": \"P-521\",\n" +
|
||||||
|
" \"kid\": \"jap-jwk-keyid\",\n" +
|
||||||
|
" \"x\": \"AF20L_FMTzA6Rl9IEYk7Ww-V06PiiQ7-cZ6p8Hgs8xha2TSC46BoZ3kZH1-aoVJUTlJCuhS5zfWcJVBA7Szx3izd\",\n" +
|
||||||
|
" \"y\": \"ARTnAphEcl9OtHJd6kDasfjNbPZrzWjt8SJFEHoxMqlwgl4dBAkO82itFfOxpvFYpei02rGSOQtambGA2u1ZwkYc\",\n" +
|
||||||
|
" \"alg\": \"ES512\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
public JwtUtilTest() {
|
||||||
|
userInfo.setId("1111");
|
||||||
|
userInfo.setUsername("rd");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createJwtTokenFromRs256() {
|
||||||
|
String jwtToken = JwtUtil.createJwtToken(clientId, userInfo, tokenExpireIn, nonce, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig().setJwksJson(rs256JwksJson)));
|
||||||
|
System.out.println(jwtToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseJwtTokenFromRs256() {
|
||||||
|
String jwt = "eyJraWQiOiJqYXAtandrLWtleWlkIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwOi8vd3d3LmJhaWR1LmNvbSIsInN1YiI6IjExMTEiLCJhdWQiOiJ4eHh4eHh4IiwiZXhwIjoxNjUwMDMxMDE4LCJpYXQiOjE2MTg0OTUwMTgsIm5vbmNlIjoiYXNkYXNkIiwidXNlcm5hbWUiOiJyZCJ9.YgqeBmlrGeauzEAwPOi_WIjG7SyLieU8sbAq-2Ptqq8bDOg0CZdKnzaU9mr-3iEoOeAzTTXh02jHzEz8hhorxi2PFnjZy4H1HSgNqGZckAvwGnN5aC_tMPhx1I_8XMZ0_ZpRiCAlV1NSedveQbCm1jJVKSCoBSLUA4hCIWAQqAR__M-de08oQ-r3HfhFZkSghbzMOI8fXMLvVLtexQAxjek6hn769x-hi-AW-DVDPB_ifUojV8TUNZWZHNj2kG89rBwLgK5LsXEBFpBFvwtfkBYPJVxiSf3cGLcUPTpipQ8buvaLXojAYwE_MXIRklUm2FMAuodQKDJunExe3rzYjw";
|
||||||
|
Map<String, Object> jwtInfo = JwtUtil.parseJwtToken(jwt, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(rs256JwksJson)
|
||||||
|
));
|
||||||
|
System.out.println(jwtInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createJwtTokenFromRs384() {
|
||||||
|
String jwtToken = JwtUtil.createJwtToken(clientId, userInfo, tokenExpireIn, nonce, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(rs384JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.RS384)
|
||||||
|
));
|
||||||
|
System.out.println(jwtToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseJwtTokenFromRs384() {
|
||||||
|
String jwt = "eyJraWQiOiJqYXAtandrLWtleWlkIiwiYWxnIjoiUlMzODQifQ.eyJpc3MiOiJodHRwOi8vd3d3LmJhaWR1LmNvbSIsInN1YiI6IjExMTEiLCJhdWQiOiJ4eHh4eHh4IiwiZXhwIjoxNjUwMDMxMDYwLCJpYXQiOjE2MTg0OTUwNjAsIm5vbmNlIjoiYXNkYXNkIiwidXNlcm5hbWUiOiJyZCJ9.fqVFn5Hawa6_sDMP8qN1GDq5TTWPJ8WobxPa_Haw6eapEx36Mgqc2Nc5OaV-ZfzqKgEGRqKuWPQl4_KgxcrnkWD2qOmThGsgLlKE8U3MPNeiyCkGTVJ6fMLwXC1lCZhjP8bSJCMDN1E-RVT1oAPGuHptqVmcaVxYDjakzfy_ofFAItFah9O1L875l172LWSeVbt7tjPkShfnjE0XVHPhs1-mG5FcZL5ScpdhZ3doDK0H1Vf5LJAeapuhL1q_zNeBX2P88kCeTy1zc7bEEWaHlA_WM_qStvrXgcFoAlpuVTOAbipyJwX26vxQTi2fKvAhZHINtL03S1un1AQGuIy3FQ";
|
||||||
|
Map<String, Object> jwtInfo = JwtUtil.parseJwtToken(jwt, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(rs384JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.RS384)
|
||||||
|
));
|
||||||
|
System.out.println(jwtInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createJwtTokenFromRs512() {
|
||||||
|
String jwtToken = JwtUtil.createJwtToken(clientId, userInfo, tokenExpireIn, nonce, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(rs512JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.RS512)
|
||||||
|
));
|
||||||
|
System.out.println(jwtToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseJwtTokenFromRs512() {
|
||||||
|
String jwt = "eyJraWQiOiJqYXAtandrLWtleWlkIiwiYWxnIjoiUlM1MTIifQ.eyJpc3MiOiJodHRwOi8vd3d3LmJhaWR1LmNvbSIsInN1YiI6IjExMTEiLCJhdWQiOiJ4eHh4eHh4IiwiZXhwIjoxNjUwMDMxMDk3LCJpYXQiOjE2MTg0OTUwOTcsIm5vbmNlIjoiYXNkYXNkIiwidXNlcm5hbWUiOiJyZCJ9.ibVDk8CxM6jbNcDGqRc-emjqmRvx4ghhSlzvv6rScC8JDmQGgEotdcmu0N5OaxQt-YZex9daAYBF3Cx09jIvjjot0Iy-0mLf1sT4tjG3K5LQ862LRao3L9MyE3Pzqhe2am9AMaGlGimCdrrAFmufSprTADw7jgLxoVIwY5ou1ei5SAO__RjZo-Nmxp8kTW2ea9zKFuhWEkjmLWdZAi6Iet8ntcSFsa1RFc05Urytu8fbOKlqQwaVLOfiaEQw6QDmd28Q7h_BFP_rbclaHaJHOjv05WMKeH5iOEN0wCz4HlZYKOLfLPzH5pZuutMdueiDdCN5WemGLeekpOcJ0BKDfw";
|
||||||
|
Map<String, Object> jwtInfo = JwtUtil.parseJwtToken(jwt, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(rs512JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.RS512)
|
||||||
|
));
|
||||||
|
System.out.println(jwtInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createJwtTokenFromEs256() {
|
||||||
|
String jwtToken = JwtUtil.createJwtToken(clientId, userInfo, tokenExpireIn, nonce, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(es256JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.ES256)
|
||||||
|
));
|
||||||
|
System.out.println(jwtToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseJwtTokenFromEs256() {
|
||||||
|
String jwt = "eyJraWQiOiJqYXAtandrLWtleWlkIiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOm51bGwsInN1YiI6IjExMTEiLCJhdWQiOiJ4eHh4eHh4IiwiZXhwIjoxNjUwMDMxMTIzLCJpYXQiOjE2MTg0OTUxMjMsIm5vbmNlIjoiYXNkYXNkIiwidXNlcm5hbWUiOiJyZCJ9.k1b3DEceONkjvOfyE3oBLoVnMNBafx8cMQPU8971D5Xmksn4nnrJl9v2DinvbCrCTc2MVqznClvuhiQ0c76aXg";
|
||||||
|
Map<String, Object> jwtInfo = JwtUtil.parseJwtToken(jwt, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(es256JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.ES256)
|
||||||
|
));
|
||||||
|
System.out.println(jwtInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createJwtTokenFromEs384() {
|
||||||
|
String jwtToken = JwtUtil.createJwtToken(clientId, userInfo, tokenExpireIn, nonce, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(es384JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.ES384)
|
||||||
|
));
|
||||||
|
System.out.println(jwtToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseJwtTokenFromEs384() {
|
||||||
|
String jwt = "eyJraWQiOiJqYXAtandrLWtleWlkIiwiYWxnIjoiRVMzODQifQ.eyJpc3MiOm51bGwsInN1YiI6IjExMTEiLCJhdWQiOiJ4eHh4eHh4IiwiZXhwIjoxNjE4NTkyMzQxLCJpYXQiOjE2MTg0OTIzNDEsIm5vbmNlIjoiYXNkYXNkIiwidXNlcm5hbWUiOm51bGx9.BhVF8JagDRjpnW8wbsNi-Fik9nVnIq8X5mpnrkpp1f6K7b1vqCuBuzmHYpy2Wwz1eVYUTa3haRay30jFC2OwzwXNMNXIdJ6X5w-KKefKtiFl_YITFQU-WDwAsPGT3ZfI";
|
||||||
|
Map<String, Object> jwtInfo = JwtUtil.parseJwtToken(jwt, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(es384JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.ES384)
|
||||||
|
));
|
||||||
|
System.out.println(jwtInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createJwtTokenFromEs512() {
|
||||||
|
String jwtToken = JwtUtil.createJwtToken(clientId, userInfo, tokenExpireIn, nonce, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(es512JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.ES512)
|
||||||
|
));
|
||||||
|
System.out.println(jwtToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseJwtTokenFromEs512() {
|
||||||
|
String jwt = "eyJraWQiOiJqYXAtandrLWtleWlkIiwiYWxnIjoiRVM1MTIifQ.eyJpc3MiOm51bGwsInN1YiI6IjExMTEiLCJhdWQiOiJ4eHh4eHh4IiwiZXhwIjoxNjE4NTkyNDQwLCJpYXQiOjE2MTg0OTI0NDAsIm5vbmNlIjoiYXNkYXNkIiwidXNlcm5hbWUiOiJyZCJ9.ARZRKO52FZe7MCKy_Kv02IodCIli6y1ZbSlWpe4Qn0sCBNLGzmcK5A0302TM9dZ8yu8TgLK9j7MbW9i6VaeDZmfwAA0_z1J1SBiIwJ38IdhISJItFBQL28KVf02zfFXfKHl2AZ9DU_liyuNsdkuV92Np-sEAoFMpkC_4cSlJqpM6T-oi";
|
||||||
|
Map<String, Object> jwtInfo = JwtUtil.parseJwtToken(jwt, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(es512JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.ES512)
|
||||||
|
));
|
||||||
|
System.out.println(jwtInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void validateJwtToken() {
|
||||||
|
String jwt = "eyJraWQiOiJqYXAtandrLWtleWlkIiwiYWxnIjoiUlMzODQifQ.eyJpc3MiOiJodHRwOi8vd3d3LmJhaWR1LmNvbSIsInN1YiI6IjExMTEiLCJhdWQiOiJ4eHh4eHh4IiwiZXhwIjoxNjUwMDMxMDYwLCJpYXQiOjE2MTg0OTUwNjAsIm5vbmNlIjoiYXNkYXNkIiwidXNlcm5hbWUiOiJyZCJ9.fqVFn5Hawa6_sDMP8qN1GDq5TTWPJ8WobxPa_Haw6eapEx36Mgqc2Nc5OaV-ZfzqKgEGRqKuWPQl4_KgxcrnkWD2qOmThGsgLlKE8U3MPNeiyCkGTVJ6fMLwXC1lCZhjP8bSJCMDN1E-RVT1oAPGuHptqVmcaVxYDjakzfy_ofFAItFah9O1L875l172LWSeVbt7tjPkShfnjE0XVHPhs1-mG5FcZL5ScpdhZ3doDK0H1Vf5LJAeapuhL1q_zNeBX2P88kCeTy1zc7bEEWaHlA_WM_qStvrXgcFoAlpuVTOAbipyJwX26vxQTi2fKvAhZHINtL03S1un1AQGuIy3FQ";
|
||||||
|
Map<String, Object> jwtInfo = JwtUtil.validateJwtToken(clientId, userInfo.getId(), jwt, new IdsConfig()
|
||||||
|
.setIssuer(issuer)
|
||||||
|
.setJwtConfig(new JwtConfig()
|
||||||
|
.setJwksJson(es512JwksJson)
|
||||||
|
.setTokenSigningAlg(TokenSigningAlg.ES512)
|
||||||
|
.setJwtVerificationType(JwtVerificationType.JWKS)
|
||||||
|
));
|
||||||
|
System.out.println(jwtInfo);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user