Selaa lähdekoodia

Metadata PEM support

MaxKey 3 vuotta sitten
vanhempi
commit
ee8b7536e1

+ 39 - 0
maxkey-common/src/main/java/org/maxkey/crypto/RSAUtils.java

@@ -25,6 +25,7 @@ import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -38,6 +39,8 @@ public final class RSAUtils {
 	public static final String PUBLIC_KEY 		= 	"RSAPublicKey";
 
 	public static final String PRIVATE_KEY 		= 	"RSAPrivateKey";
+	
+	public static final int BASE64ARRAY_SIZE	= 64;
 
 	public static Map<String, Object> genKeyPair() throws Exception {
 		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORTHM);
@@ -173,5 +176,41 @@ public final class RSAUtils {
 
 		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();
+	}
+	
 
 }

+ 53 - 1
maxkey-common/src/main/java/org/maxkey/crypto/jose/keystore/JWKSetKeyStore.java

@@ -18,12 +18,20 @@ package org.maxkey.crypto.jose.keystore;
 
 import com.google.common.base.Charsets;
 import com.google.common.io.CharStreams;
+import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.jwk.JWK;
 import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.jose.jwk.RSAKey;
+
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.security.PublicKey;
 import java.text.ParseException;
 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.LoggerFactory;
 import org.springframework.core.io.Resource;
@@ -131,5 +139,49 @@ public class JWKSetKeyStore {
         }
         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();
+	}
 }

+ 29 - 18
maxkey-protocols/maxkey-protocol-jwt/src/main/java/org/maxkey/authz/token/endpoint/JwtAuthorizeEndpoint.java

@@ -21,7 +21,6 @@
 package org.maxkey.authz.token.endpoint;
 
 import java.lang.reflect.InvocationTargetException;
-
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 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.configuration.ApplicationConfig;
 import org.maxkey.constants.ConstsBoolean;
+import org.maxkey.constants.ContentType;
 import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
 import org.maxkey.entity.apps.Apps;
 import org.maxkey.entity.apps.AppsJwtDetails;
 import org.maxkey.persistence.service.AppsJwtDetailsService;
-import org.maxkey.pretty.PrettyFactory;
 import org.maxkey.util.Instance;
+import org.maxkey.web.HttpRequestAdapter;
 import org.maxkey.web.WebConstants;
 import org.maxkey.web.WebContext;
 import org.slf4j.Logger;
@@ -138,27 +138,38 @@ public class JwtAuthorizeEndpoint  extends AuthorizeBaseEndpoint{
 	}
 
 	@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
 	public String  metadata(HttpServletRequest request,
-			HttpServletResponse response, @PathVariable("appid") String appId) {
-		appId = appId.substring(WebConstants.MXK_METADATA_PREFIX.length(), appId.length());
+			HttpServletResponse response, 
+			@PathVariable("appid") String appId, 
+			@PathVariable("mediaType") String mediaType) {
 		AppsJwtDetails jwtDetails = jwtDetailsService.getAppDetails(appId);
-		String jwkSetString = "";
-		if(!jwtDetails.getSignature().equalsIgnoreCase("none")) {
-			jwkSetString = jwtDetails.getSignatureKey();
-		}
-		if(!jwtDetails.getAlgorithm().equalsIgnoreCase("none")) {
-			if(StringUtils.isBlank(jwkSetString)) {
-				jwkSetString = jwtDetails.getAlgorithmKey();
+		if(jwtDetails != null) {
+			String jwkSetString = "";
+			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();
+				}
+			}
+			 
+			JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": [" + jwkSetString + "]}");
+			if(StringUtils.isNotBlank(mediaType) 
+					&& mediaType.equalsIgnoreCase(HttpRequestAdapter.MediaType.XML)) {
+				response.setContentType(ContentType.APPLICATION_XML_UTF8);
 			}else {
-				jwkSetString = jwkSetString + "," +jwtDetails.getAlgorithmKey();
+				response.setContentType(ContentType.APPLICATION_JSON_UTF8);
 			}
+			return jwkSetKeyStore.toString(mediaType);
+			
 		}
-		 
-		JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": [" + jwkSetString + "]}");
-		
-		return PrettyFactory.getJsonPretty().format(
-				jwkSetKeyStore.getJwkSet().toPublicJWKSet().toString());
+		return appId + " not exist.";
 	}
 }

+ 28 - 15
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/endpoint/AuthorizationEndpoint.java

@@ -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.implicit.ImplicitTokenRequest;
 import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestValidator;
+import org.maxkey.constants.ContentType;
 import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
 import org.maxkey.util.HttpEncoder;
 import org.maxkey.entity.apps.Apps;
 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.WebContext;
 import org.slf4j.Logger;
@@ -291,27 +292,39 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
 	}
 	
 	@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
 	public String  metadata(HttpServletRequest request,
-			HttpServletResponse response, @PathVariable("appid") String appId) {
-		appId = appId.substring(WebConstants.MXK_METADATA_PREFIX.length(), appId.length());
+			HttpServletResponse response, 
+			@PathVariable("appid") String appId,
+			@PathVariable("mediaType") String mediaType) {
 		ClientDetails  clientDetails = getClientDetailsService().loadClientByClientId(appId,true);
-		String jwkSetString = "";
-		if(!clientDetails.getSignature().equalsIgnoreCase("none")) {
-			jwkSetString = clientDetails.getSignatureKey();
-		}
-		if(!clientDetails.getAlgorithm().equalsIgnoreCase("none")) {
-			if(!StringUtils.hasText(jwkSetString)) {
-				jwkSetString = clientDetails.getAlgorithmKey();
+		if(clientDetails != null) {
+			String jwkSetString = "";
+			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();
+				}
+			}
+			JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": [" + jwkSetString + "]}");
+			
+			if(StringUtils.hasText(mediaType) 
+					&& mediaType.equalsIgnoreCase(HttpRequestAdapter.MediaType.XML)) {
+				response.setContentType(ContentType.APPLICATION_XML_UTF8);
 			}else {
-				jwkSetString = jwkSetString + "," +clientDetails.getAlgorithmKey();
+				response.setContentType(ContentType.APPLICATION_JSON_UTF8);
 			}
+			return jwkSetKeyStore.toString(mediaType);
 		}
-		JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": [" + jwkSetString + "]}");
 		
-		return PrettyFactory.getJsonPretty().format(
-				jwkSetKeyStore.getJwkSet().toPublicJWKSet().toString());
+		return appId + " not exist.";
 	}
 
 	// We need explicit approval from the user.

+ 1 - 2
maxkey-protocols/maxkey-protocol-saml-2.0/src/main/java/org/maxkey/authz/saml20/metadata/endpoint/SamlMetadataEndpoint.java

@@ -76,12 +76,11 @@ public class SamlMetadataEndpoint {
 	private Credential signingCredential;
 
 	@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
 	public String  metadata(HttpServletRequest request,
 			HttpServletResponse response, @PathVariable("appid") String appId) {
 	    response.setContentType(ContentType.APPLICATION_XML_UTF8);
-	    appId = appId.substring(WebConstants.MXK_METADATA_PREFIX.length(), appId.length());
 		if(signingCredential == null){
 	        TrustResolver trustResolver = new TrustResolver();
 	        CredentialResolver credentialResolver=(CredentialResolver)trustResolver.buildKeyStoreCredentialResolver(