mirror of
https://gitee.com/dromara/MaxKey.git
synced 2025-12-07 01:18:27 +08:00
Metadata PEM support
This commit is contained in:
parent
743037b6cc
commit
ee8b7536e1
@ -25,6 +25,7 @@ import java.security.interfaces.RSAPrivateKey;
|
|||||||
import java.security.interfaces.RSAPublicKey;
|
import java.security.interfaces.RSAPublicKey;
|
||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -38,6 +39,8 @@ public final class RSAUtils {
|
|||||||
public static final String PUBLIC_KEY = "RSAPublicKey";
|
public static final String PUBLIC_KEY = "RSAPublicKey";
|
||||||
|
|
||||||
public static final String PRIVATE_KEY = "RSAPrivateKey";
|
public static final String PRIVATE_KEY = "RSAPrivateKey";
|
||||||
|
|
||||||
|
public static final int BASE64ARRAY_SIZE = 64;
|
||||||
|
|
||||||
public static Map<String, Object> genKeyPair() throws Exception {
|
public static Map<String, Object> genKeyPair() throws Exception {
|
||||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORTHM);
|
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORTHM);
|
||||||
@ -173,5 +176,41 @@ public final class RSAUtils {
|
|||||||
|
|
||||||
return cipher.doFinal(data);
|
return cipher.doFinal(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPublicKeyPEM(byte[] encoded) {
|
||||||
|
StringBuffer base64String =
|
||||||
|
new StringBuffer("");
|
||||||
|
base64String.append("-----BEGIN PUBLIC KEY-----").append("\n");
|
||||||
|
base64String.append(getBase64PEM(encoded));
|
||||||
|
base64String.append("-----END PUBLIC KEY-------").append("\n");
|
||||||
|
return base64String.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPrivateKeyPEM(byte[] encoded) {
|
||||||
|
StringBuffer base64String =
|
||||||
|
new StringBuffer("");
|
||||||
|
base64String.append("-----BEGIN RSA PRIVATE KEY-----").append("\n");
|
||||||
|
base64String.append(getBase64PEM(encoded));
|
||||||
|
base64String.append("-----END RSA PRIVATE KEY-------").append("\n");
|
||||||
|
return base64String.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getBase64PEM(byte[] encoded) {
|
||||||
|
String base64String = Base64.getEncoder().encodeToString(encoded);
|
||||||
|
StringBuffer base64ArrayString = new StringBuffer("");
|
||||||
|
int startPosition = 0;
|
||||||
|
int endPosition = BASE64ARRAY_SIZE;
|
||||||
|
while(endPosition < base64String.length()) {
|
||||||
|
base64ArrayString.append(base64String.substring(startPosition, endPosition)).append("\n");
|
||||||
|
startPosition = endPosition;
|
||||||
|
endPosition = endPosition + BASE64ARRAY_SIZE;
|
||||||
|
}
|
||||||
|
if(startPosition < base64String.length()) {
|
||||||
|
base64ArrayString.append(base64String.substring(startPosition)).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64ArrayString.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,12 +18,20 @@ package org.maxkey.crypto.jose.keystore;
|
|||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.io.CharStreams;
|
import com.google.common.io.CharStreams;
|
||||||
|
import com.nimbusds.jose.JOSEException;
|
||||||
import com.nimbusds.jose.jwk.JWK;
|
import com.nimbusds.jose.jwk.JWK;
|
||||||
import com.nimbusds.jose.jwk.JWKSet;
|
import com.nimbusds.jose.jwk.JWKSet;
|
||||||
|
import com.nimbusds.jose.jwk.RSAKey;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.security.PublicKey;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.maxkey.crypto.RSAUtils;
|
||||||
|
import org.maxkey.pretty.PrettyFactory;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
@ -131,5 +139,49 @@ public class JWKSetKeyStore {
|
|||||||
}
|
}
|
||||||
return jwkSet.getKeys();
|
return jwkSet.getKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString(String mediaType){
|
||||||
|
StringBuffer metaDataString = new StringBuffer("");
|
||||||
|
if(StringUtils.isNotBlank(mediaType) && mediaType.equalsIgnoreCase("XML")) {
|
||||||
|
metaDataString.append("<RSAKeyValue>").append("\n");
|
||||||
|
for(JWK jwk : jwkSet.getKeys()) {
|
||||||
|
RSAKey rsaKey = jwk.toRSAKey();
|
||||||
|
PublicKey publicKey;
|
||||||
|
try {
|
||||||
|
publicKey = rsaKey.toPublicKey();
|
||||||
|
metaDataString.append("<Modulus>").append("\n");
|
||||||
|
metaDataString.append(RSAUtils.getPublicKeyPEM(publicKey.getEncoded()));
|
||||||
|
metaDataString.append("</Modulus>").append("\n");
|
||||||
|
//keyID
|
||||||
|
metaDataString.append("<Algorithm>");
|
||||||
|
metaDataString.append(rsaKey.getAlgorithm());
|
||||||
|
metaDataString.append("</Algorithm>").append("\n");
|
||||||
|
|
||||||
|
metaDataString.append("<KeyID>");
|
||||||
|
metaDataString.append(rsaKey.getKeyID());
|
||||||
|
metaDataString.append("</KeyID>").append("\n");
|
||||||
|
|
||||||
|
metaDataString.append("<KeyType>");
|
||||||
|
metaDataString.append(rsaKey.getKeyType());
|
||||||
|
metaDataString.append("</KeyType>").append("\n");
|
||||||
|
|
||||||
|
metaDataString.append("<Format>");
|
||||||
|
metaDataString.append(publicKey.getFormat());
|
||||||
|
metaDataString.append("</Format>");
|
||||||
|
|
||||||
|
metaDataString.append("<PublicExponent>");
|
||||||
|
metaDataString.append(rsaKey.getPublicExponent());
|
||||||
|
metaDataString.append("</PublicExponent>").append("\n");
|
||||||
|
} catch (JOSEException e) {
|
||||||
|
_logger.error("JOSEException ", mediaType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
metaDataString.append("</RSAKeyValue>");
|
||||||
|
}else {
|
||||||
|
metaDataString.append(PrettyFactory.getJsonPretty().format(
|
||||||
|
jwkSet.toPublicJWKSet().toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return metaDataString.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,6 @@
|
|||||||
package org.maxkey.authz.token.endpoint;
|
package org.maxkey.authz.token.endpoint;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
@ -34,12 +33,13 @@ import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter;
|
|||||||
import org.maxkey.authz.jwt.endpoint.adapter.JwtAdapter;
|
import org.maxkey.authz.jwt.endpoint.adapter.JwtAdapter;
|
||||||
import org.maxkey.configuration.ApplicationConfig;
|
import org.maxkey.configuration.ApplicationConfig;
|
||||||
import org.maxkey.constants.ConstsBoolean;
|
import org.maxkey.constants.ConstsBoolean;
|
||||||
|
import org.maxkey.constants.ContentType;
|
||||||
import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
|
import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
|
||||||
import org.maxkey.entity.apps.Apps;
|
import org.maxkey.entity.apps.Apps;
|
||||||
import org.maxkey.entity.apps.AppsJwtDetails;
|
import org.maxkey.entity.apps.AppsJwtDetails;
|
||||||
import org.maxkey.persistence.service.AppsJwtDetailsService;
|
import org.maxkey.persistence.service.AppsJwtDetailsService;
|
||||||
import org.maxkey.pretty.PrettyFactory;
|
|
||||||
import org.maxkey.util.Instance;
|
import org.maxkey.util.Instance;
|
||||||
|
import org.maxkey.web.HttpRequestAdapter;
|
||||||
import org.maxkey.web.WebConstants;
|
import org.maxkey.web.WebConstants;
|
||||||
import org.maxkey.web.WebContext;
|
import org.maxkey.web.WebContext;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -138,27 +138,38 @@ public class JwtAuthorizeEndpoint extends AuthorizeBaseEndpoint{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "JWT JWK元数据接口", description = "参数mxk_metadata_APPID",method="GET")
|
@Operation(summary = "JWT JWK元数据接口", description = "参数mxk_metadata_APPID",method="GET")
|
||||||
@RequestMapping(value = "/metadata/jwt/{appid}.json",produces = "application/json", method={RequestMethod.POST, RequestMethod.GET})
|
@RequestMapping(
|
||||||
|
value = "/metadata/jwt/" + WebConstants.MXK_METADATA_PREFIX + "{appid}.{mediaType}",
|
||||||
|
method={RequestMethod.POST, RequestMethod.GET})
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public String metadata(HttpServletRequest request,
|
public String metadata(HttpServletRequest request,
|
||||||
HttpServletResponse response, @PathVariable("appid") String appId) {
|
HttpServletResponse response,
|
||||||
appId = appId.substring(WebConstants.MXK_METADATA_PREFIX.length(), appId.length());
|
@PathVariable("appid") String appId,
|
||||||
|
@PathVariable("mediaType") String mediaType) {
|
||||||
AppsJwtDetails jwtDetails = jwtDetailsService.getAppDetails(appId);
|
AppsJwtDetails jwtDetails = jwtDetailsService.getAppDetails(appId);
|
||||||
String jwkSetString = "";
|
if(jwtDetails != null) {
|
||||||
if(!jwtDetails.getSignature().equalsIgnoreCase("none")) {
|
String jwkSetString = "";
|
||||||
jwkSetString = jwtDetails.getSignatureKey();
|
if(!jwtDetails.getSignature().equalsIgnoreCase("none")) {
|
||||||
}
|
jwkSetString = jwtDetails.getSignatureKey();
|
||||||
if(!jwtDetails.getAlgorithm().equalsIgnoreCase("none")) {
|
|
||||||
if(StringUtils.isBlank(jwkSetString)) {
|
|
||||||
jwkSetString = jwtDetails.getAlgorithmKey();
|
|
||||||
}else {
|
|
||||||
jwkSetString = jwkSetString + "," +jwtDetails.getAlgorithmKey();
|
|
||||||
}
|
}
|
||||||
|
if(!jwtDetails.getAlgorithm().equalsIgnoreCase("none")) {
|
||||||
|
if(StringUtils.isBlank(jwkSetString)) {
|
||||||
|
jwkSetString = jwtDetails.getAlgorithmKey();
|
||||||
|
}else {
|
||||||
|
jwkSetString = jwkSetString + "," +jwtDetails.getAlgorithmKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": [" + jwkSetString + "]}");
|
||||||
|
if(StringUtils.isNotBlank(mediaType)
|
||||||
|
&& mediaType.equalsIgnoreCase(HttpRequestAdapter.MediaType.XML)) {
|
||||||
|
response.setContentType(ContentType.APPLICATION_XML_UTF8);
|
||||||
|
}else {
|
||||||
|
response.setContentType(ContentType.APPLICATION_JSON_UTF8);
|
||||||
|
}
|
||||||
|
return jwkSetKeyStore.toString(mediaType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return appId + " not exist.";
|
||||||
JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": [" + jwkSetString + "]}");
|
|
||||||
|
|
||||||
return PrettyFactory.getJsonPretty().format(
|
|
||||||
jwkSetKeyStore.getJwkSet().toPublicJWKSet().toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,11 +42,12 @@ import org.maxkey.authz.oauth2.provider.approval.UserApprovalHandler;
|
|||||||
import org.maxkey.authz.oauth2.provider.code.AuthorizationCodeServices;
|
import org.maxkey.authz.oauth2.provider.code.AuthorizationCodeServices;
|
||||||
import org.maxkey.authz.oauth2.provider.implicit.ImplicitTokenRequest;
|
import org.maxkey.authz.oauth2.provider.implicit.ImplicitTokenRequest;
|
||||||
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestValidator;
|
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestValidator;
|
||||||
|
import org.maxkey.constants.ContentType;
|
||||||
import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
|
import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
|
||||||
import org.maxkey.util.HttpEncoder;
|
import org.maxkey.util.HttpEncoder;
|
||||||
import org.maxkey.entity.apps.Apps;
|
import org.maxkey.entity.apps.Apps;
|
||||||
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
|
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
|
||||||
import org.maxkey.pretty.PrettyFactory;
|
import org.maxkey.web.HttpRequestAdapter;
|
||||||
import org.maxkey.web.WebConstants;
|
import org.maxkey.web.WebConstants;
|
||||||
import org.maxkey.web.WebContext;
|
import org.maxkey.web.WebContext;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -291,27 +292,39 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "OAuth JWk 元数据接口", description = "参数mxk_metadata_APPID",method="GET")
|
@Operation(summary = "OAuth JWk 元数据接口", description = "参数mxk_metadata_APPID",method="GET")
|
||||||
@RequestMapping(value = "/metadata/oauth/v20/{appid}.json",produces = "application/json", method={RequestMethod.POST, RequestMethod.GET})
|
@RequestMapping(
|
||||||
|
value = "/metadata/oauth/v20/" + WebConstants.MXK_METADATA_PREFIX + "{appid}.{mediaType}",
|
||||||
|
method={RequestMethod.POST, RequestMethod.GET})
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public String metadata(HttpServletRequest request,
|
public String metadata(HttpServletRequest request,
|
||||||
HttpServletResponse response, @PathVariable("appid") String appId) {
|
HttpServletResponse response,
|
||||||
appId = appId.substring(WebConstants.MXK_METADATA_PREFIX.length(), appId.length());
|
@PathVariable("appid") String appId,
|
||||||
|
@PathVariable("mediaType") String mediaType) {
|
||||||
ClientDetails clientDetails = getClientDetailsService().loadClientByClientId(appId,true);
|
ClientDetails clientDetails = getClientDetailsService().loadClientByClientId(appId,true);
|
||||||
String jwkSetString = "";
|
if(clientDetails != null) {
|
||||||
if(!clientDetails.getSignature().equalsIgnoreCase("none")) {
|
String jwkSetString = "";
|
||||||
jwkSetString = clientDetails.getSignatureKey();
|
if(!clientDetails.getSignature().equalsIgnoreCase("none")) {
|
||||||
}
|
jwkSetString = clientDetails.getSignatureKey();
|
||||||
if(!clientDetails.getAlgorithm().equalsIgnoreCase("none")) {
|
|
||||||
if(!StringUtils.hasText(jwkSetString)) {
|
|
||||||
jwkSetString = clientDetails.getAlgorithmKey();
|
|
||||||
}else {
|
|
||||||
jwkSetString = jwkSetString + "," +clientDetails.getAlgorithmKey();
|
|
||||||
}
|
}
|
||||||
|
if(!clientDetails.getAlgorithm().equalsIgnoreCase("none")) {
|
||||||
|
if(!StringUtils.hasText(jwkSetString)) {
|
||||||
|
jwkSetString = clientDetails.getAlgorithmKey();
|
||||||
|
}else {
|
||||||
|
jwkSetString = jwkSetString + "," +clientDetails.getAlgorithmKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": [" + jwkSetString + "]}");
|
||||||
|
|
||||||
|
if(StringUtils.hasText(mediaType)
|
||||||
|
&& mediaType.equalsIgnoreCase(HttpRequestAdapter.MediaType.XML)) {
|
||||||
|
response.setContentType(ContentType.APPLICATION_XML_UTF8);
|
||||||
|
}else {
|
||||||
|
response.setContentType(ContentType.APPLICATION_JSON_UTF8);
|
||||||
|
}
|
||||||
|
return jwkSetKeyStore.toString(mediaType);
|
||||||
}
|
}
|
||||||
JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": [" + jwkSetString + "]}");
|
|
||||||
|
|
||||||
return PrettyFactory.getJsonPretty().format(
|
return appId + " not exist.";
|
||||||
jwkSetKeyStore.getJwkSet().toPublicJWKSet().toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need explicit approval from the user.
|
// We need explicit approval from the user.
|
||||||
|
|||||||
@ -76,12 +76,11 @@ public class SamlMetadataEndpoint {
|
|||||||
private Credential signingCredential;
|
private Credential signingCredential;
|
||||||
|
|
||||||
@Operation(summary = "SAML 2.0 元数据接口", description = "参数mxk_metadata_APPID",method="GET")
|
@Operation(summary = "SAML 2.0 元数据接口", description = "参数mxk_metadata_APPID",method="GET")
|
||||||
@RequestMapping(value = "/{appid}.xml",produces = "application/xml", method={RequestMethod.POST, RequestMethod.GET})
|
@RequestMapping(value = "/" + WebConstants.MXK_METADATA_PREFIX + "{appid}.xml",produces = "application/xml", method={RequestMethod.POST, RequestMethod.GET})
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public String metadata(HttpServletRequest request,
|
public String metadata(HttpServletRequest request,
|
||||||
HttpServletResponse response, @PathVariable("appid") String appId) {
|
HttpServletResponse response, @PathVariable("appid") String appId) {
|
||||||
response.setContentType(ContentType.APPLICATION_XML_UTF8);
|
response.setContentType(ContentType.APPLICATION_XML_UTF8);
|
||||||
appId = appId.substring(WebConstants.MXK_METADATA_PREFIX.length(), appId.length());
|
|
||||||
if(signingCredential == null){
|
if(signingCredential == null){
|
||||||
TrustResolver trustResolver = new TrustResolver();
|
TrustResolver trustResolver = new TrustResolver();
|
||||||
CredentialResolver credentialResolver=(CredentialResolver)trustResolver.buildKeyStoreCredentialResolver(
|
CredentialResolver credentialResolver=(CredentialResolver)trustResolver.buildKeyStoreCredentialResolver(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user