Преглед изворни кода

SAML Metadata URL配置读取

Crystal.Sea пре 4 година
родитељ
комит
2f936c80dd

+ 5 - 0
ReleaseNotes.txt

@@ -13,6 +13,10 @@
 	*(MAXKEY-201012)  密码策略提示参数问题修复
 	*(MAXKEY-201013)  SAML 2.0 Metadata优化
 	*(MAXKEY-201014)  HandlerInterceptorAdapter@deprecated  调整为 AsyncHandlerInterceptor 
+	*(MAXKEY-201015)  mybatis-jpa升级,添加@Entity和@Transient支持,优化update时字段为null的处理,SQL代码优化 
+	*(MAXKEY-201016)  README中文和英文支持
+	*(MAXKEY-201017)  认证失败时,authentication 空指针异常
+	*(MAXKEY-201018)  SAML Metadata URL配置读取
 	*(MAXKEY-201020)  依赖jar引用、更新和升级
 		not-yet-commons-ssl 0.3.9
 		log4j          	 	2.14.0
@@ -21,6 +25,7 @@
 		springSecurity 	 	5.4.1
 		springData    	 	2.4.1
 		springSession    	2.4.1
+		mybatis-jpa-extra	2.2
 		
 
 MaxKey v 2.3.0 GA	2020/11/12

+ 2 - 1
maxkey-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java

@@ -118,7 +118,8 @@ public abstract class AbstractAuthenticationProvider {
             String message = "Unexpected exception in " + getProviderName() + " authentication:";
             _logger.error("Login error " + message, e);
         }
-        if (!authentication.isAuthenticated()) {
+        
+        if (authentication== null || !authentication.isAuthenticated()) {
             return authentication;
         }
 

+ 35 - 12
maxkey-core/src/main/java/org/maxkey/domain/apps/AppsSAML20Details.java

@@ -17,6 +17,8 @@
 
 package org.maxkey.domain.apps;
 
+import java.security.cert.X509Certificate;
+
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
@@ -82,11 +84,18 @@ public class AppsSAML20Details extends Apps {
     /**
      * for upload
      */
-    private MultipartFile certMetaFile;
+    private MultipartFile metaFile;
     /**
-     * metadata or certificate
+     * metadata_file metadata_url or certificate
      */
     private String fileType;
+    
+    X509Certificate trustCert = null;
+    /**
+     * metadata Url
+     */
+    @Column
+    private String metaUrl;
 
     /**
      * 0 original 1 uppercase 2 lowercase
@@ -248,6 +257,14 @@ public class AppsSAML20Details extends Apps {
         this.nameidFormat = nameidFormat;
     }
 
+    public X509Certificate getTrustCert() {
+        return trustCert;
+    }
+
+    public void setTrustCert(X509Certificate trustCert) {
+        this.trustCert = trustCert;
+    }
+
     /**
      * @return the validityInterval
      */
@@ -262,18 +279,14 @@ public class AppsSAML20Details extends Apps {
         this.validityInterval = validityInterval;
     }
 
-    /**
-     * @return the certMetaFile
-     */
-    public MultipartFile getCertMetaFile() {
-        return certMetaFile;
+  
+
+    public MultipartFile getMetaFile() {
+        return metaFile;
     }
 
-    /**
-     * @param certMetaFile the certMetaFile to set
-     */
-    public void setCertMetaFile(MultipartFile certMetaFile) {
-        this.certMetaFile = certMetaFile;
+    public void setMetaFile(MultipartFile metaFile) {
+        this.metaFile = metaFile;
     }
 
     /**
@@ -338,6 +351,14 @@ public class AppsSAML20Details extends Apps {
         this.nameIdSuffix = nameIdSuffix;
     }
 
+    public String getMetaUrl() {
+        return metaUrl;
+    }
+
+    public void setMetaUrl(String metaUrl) {
+        this.metaUrl = metaUrl;
+    }
+
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
@@ -371,6 +392,8 @@ public class AppsSAML20Details extends Apps {
         builder.append(encrypted);
         builder.append(", fileType=");
         builder.append(fileType);
+        builder.append(", metaUrl=");
+        builder.append(metaUrl);
         builder.append(", nameIdConvert=");
         builder.append(nameIdConvert);
         builder.append(", nameIdSuffix=");

+ 1 - 0
maxkey-persistence/src/main/resources/org/maxkey/persistence/mapper/xml/mysql/AppsSaml20DetailsMapper.xml

@@ -19,6 +19,7 @@
     		SVD.NAMEIDCONVERT,
     		SVD.SIGNATURE,
     		SVD.DIGESTMETHOD,
+    		SVD.METAURL,
 			APP.*
     	FROM 
     		MXK_APPS_SAML_V20_DETAILS SVD,

+ 76 - 49
maxkey-web-manage/src/main/java/org/maxkey/web/apps/contorller/SAML20DetailsController.java

@@ -21,8 +21,10 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.security.KeyStore;
 import java.security.cert.X509Certificate;
-import java.util.List;
-
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
 import org.maxkey.authz.saml20.metadata.MetadataDescriptorUtil;
 import org.maxkey.configuration.ApplicationConfig;
 import org.maxkey.constants.ConstantsOperateMessage;
@@ -151,58 +153,83 @@ public class SAML20DetailsController   extends BaseAppContorller {
 		
 		super.transform(samlDetails);
 		
-		X509Certificate trustCert = null;
-		if (null!=samlDetails.getCertMetaFile()&&!samlDetails.getCertMetaFile().isEmpty()) {
-			if(null==samlDetails.getFileType()||samlDetails.getFileType().equals("certificate")){//certificate file
-				try {
-					InputStream isCert = samlDetails.getCertMetaFile().getInputStream();
-					trustCert = X509CertUtils.loadCertFromInputStream(isCert);
+		if(null==samlDetails.getFileType()||samlDetails.getFileType().equals("certificate")){//certificate file
+			try {
+			    if (null!=samlDetails.getMetaFile()&&!samlDetails.getMetaFile().isEmpty()) {
+					InputStream isCert = samlDetails.getMetaFile().getInputStream();
+					X509Certificate trustCert = X509CertUtils.loadCertFromInputStream(isCert);
+					samlDetails.setTrustCert(trustCert);
 					isCert.close();
-				} catch (IOException e) {
-					_logger.error("read certificate file error .", e);
-					throw new Exception("read certificate file error", e);
-				}
-			}else if(samlDetails.getFileType().equals("metadata")){//metadata file
-				EntityDescriptor entityDescriptor;
-				try {
-					entityDescriptor = MetadataDescriptorUtil.getInstance().getEntityDescriptor(samlDetails.getCertMetaFile().getInputStream());
-				} catch (IOException e) {
-					_logger.error("metadata  file resolve error .", e);
-					throw new Exception("metadata  file resolve error", e);
-				}
-				SPSSODescriptor sPSSODescriptor = entityDescriptor.getSPSSODescriptor(SAMLConstants.SAML20P_NS);
-				String b64Encoder = sPSSODescriptor.getKeyDescriptors().get(0).getKeyInfo().getX509Datas().get(0).getX509Certificates().get(0).getValue();
-
-				trustCert = X509CertUtils.loadCertFromB64Encoded(b64Encoder);
-
-				samlDetails.setSpAcsUrl(sPSSODescriptor.getAssertionConsumerServices().get(0).getLocation());
-				samlDetails.setEntityId(entityDescriptor.getEntityID());
-
-				_logger.info("SPSSODescriptor EntityID"+ entityDescriptor.getEntityID());
-			}
-
-			samlDetails.setCertSubject(trustCert.getSubjectDN().getName());
-			samlDetails.setCertExpiration(trustCert.getNotAfter().toString());
-
-			samlDetails.setCertIssuer(NameUtil.getCommonName(trustCert.getIssuerX500Principal()));
-			
-			KeyStore keyStore = KeyStoreUtil.clone(idpKeyStoreLoader.getKeyStore(),idpKeyStoreLoader.getKeystorePassword());
-
-			KeyStore trustKeyStore = null;
-			if (!samlDetails.getEntityId().equals("")) {
-				trustKeyStore = KeyStoreUtil.importTrustCertificate(keyStore,trustCert, samlDetails.getEntityId());
-			} else {
-				trustKeyStore = KeyStoreUtil.importTrustCertificate(keyStore,trustCert);
+			    }
+			} catch (IOException e) {
+				_logger.error("read certificate file error .", e);
+				throw new Exception("read certificate file error", e);
 			}
-
-			byte[] keyStoreByte = KeyStoreUtil.keyStore2Bytes(trustKeyStore,idpKeyStoreLoader.getKeystorePassword());
-
-			// store KeyStore content
-			samlDetails.setKeyStore(keyStoreByte);
-		} 
+		}else if(samlDetails.getFileType().equals("metadata_file")){//metadata file
+		    if (null!=samlDetails.getMetaFile()&&!samlDetails.getMetaFile().isEmpty()) {
+		        samlDetails = resolveMetaData(samlDetails,samlDetails.getMetaFile().getInputStream());
+		    }
+		}else if(samlDetails.getFileType().equals("metadata_url")){//metadata url
+		    CloseableHttpClient httpClient = HttpClients.createDefault();
+		    HttpPost post = new HttpPost(samlDetails.getMetaUrl());
+            CloseableHttpResponse response = httpClient.execute(post);
+            samlDetails = resolveMetaData(samlDetails,response.getEntity().getContent());;
+            response.close();
+            httpClient.close();
+		}
+		
+		if(samlDetails.getTrustCert()!=null) {
+    		samlDetails.setCertSubject(samlDetails.getTrustCert().getSubjectDN().getName());
+    		samlDetails.setCertExpiration(samlDetails.getTrustCert().getNotAfter().toString());
+    
+    		samlDetails.setCertIssuer(NameUtil.getCommonName(samlDetails.getTrustCert().getIssuerX500Principal()));
+    		
+    		KeyStore keyStore = KeyStoreUtil.clone(idpKeyStoreLoader.getKeyStore(),idpKeyStoreLoader.getKeystorePassword());
+    
+    		KeyStore trustKeyStore = null;
+    		if (!samlDetails.getEntityId().equals("")) {
+    			trustKeyStore = KeyStoreUtil.importTrustCertificate(keyStore,samlDetails.getTrustCert(), samlDetails.getEntityId());
+    		} else {
+    			trustKeyStore = KeyStoreUtil.importTrustCertificate(keyStore,samlDetails.getTrustCert());
+    		}
+    
+    		byte[] keyStoreByte = KeyStoreUtil.keyStore2Bytes(trustKeyStore,idpKeyStoreLoader.getKeystorePassword());
+    
+    		// store KeyStore content
+    		samlDetails.setKeyStore(keyStoreByte);
+		}
 		
 		return samlDetails;
 	}
 	
+	public AppsSAML20Details resolveMetaData(AppsSAML20Details samlDetails,InputStream inputStream) throws Exception {
+	    X509Certificate trustCert = null;
+	    EntityDescriptor entityDescriptor;
+        try {
+            entityDescriptor = MetadataDescriptorUtil.getInstance().getEntityDescriptor(inputStream);
+        } catch (IOException e) {
+            _logger.error("metadata  file resolve error .", e);
+            throw new Exception("metadata  file resolve error", e);
+        }
+        SPSSODescriptor sPSSODescriptor = entityDescriptor.getSPSSODescriptor(SAMLConstants.SAML20P_NS);
+        String b64Encoder = sPSSODescriptor.getKeyDescriptors().get(0).getKeyInfo().getX509Datas().get(0).getX509Certificates().get(0).getValue();
+
+        trustCert = X509CertUtils.loadCertFromB64Encoded(b64Encoder);
+        
+        samlDetails.setTrustCert(trustCert);
+        samlDetails.setSpAcsUrl(sPSSODescriptor.getAssertionConsumerServices().get(0).getLocation());
+        samlDetails.setEntityId(entityDescriptor.getEntityID());
+        
+        if(samlDetails.getIssuer()==null || samlDetails.getIssuer().equals("")) {
+            samlDetails.setIssuer(entityDescriptor.getEntityID());
+        }
+        
+        if(samlDetails.getAudience()==null || samlDetails.getAudience().equals("")) {
+            samlDetails.setAudience(entityDescriptor.getEntityID());
+        }
+
+        _logger.info("SPSSODescriptor EntityID "+ entityDescriptor.getEntityID());
+        return samlDetails;
+	}
 	
 }

+ 3 - 2
maxkey-web-manage/src/main/resources/messages/message.properties

@@ -361,15 +361,16 @@ apps.saml.fileType=\u8bc1\u4e66\u7c7b\u578b
 apps.saml.nameIdConvert=NameId Convert
 apps.saml.target=\u76ee\u6807\u5730\u5740
 apps.saml.metadata.telephoneNumber=\u7535\u8bdd\u53f7\u7801
-apps.saml.fileType.metadata=SAML\u5143\u6570\u636e
+apps.saml.fileType.metadata.file=SAML\u5143\u6570\u636e\u6587\u4ef6
+apps.saml.fileType.metadata.url=SAML\u5143\u6570\u636e\u5730\u5740
 apps.saml.fileType.certificate=\u8bc1\u4e66
+apps.saml.metaFile=SAML\u5143\u6570\u636e
 apps.saml.metadata.givenName=\u540d
 apps.saml.issuer=Issuer
 apps.saml.nameIdConvert.upperCase=\u5927\u5199
 apps.saml.metadata.orgURL=\u7ec4\u7ec7\u7ad9\u70b9
 apps.saml.metadata.info=SAML V2.0 \u5143\u6570\u636e\u914d\u7f6e
 apps.saml.certSubject=\u8bc1\u4e66\u4e3b\u9898
-apps.saml.certMetaFile=\u8bc1\u4e66\u6587\u4ef6
 apps.saml.encrypted.no=\u4e0d\u52a0\u5bc6
 apps.saml.binding=Binding
 apps.saml.metadata.surName=\u59d3

+ 3 - 2
maxkey-web-manage/src/main/resources/messages/message_en.properties

@@ -360,15 +360,16 @@ apps.saml.fileType=fileType
 apps.saml.nameIdConvert=NameId Convert
 apps.saml.target=target
 apps.saml.metadata.telephoneNumber=telephoneNumber
-apps.saml.fileType.metadata=SAML Metadata Type
+apps.saml.fileType.metadata.file=SAML Metadata File
+apps.saml.fileType.metadata.url=SAML Metadata Url
 apps.saml.fileType.certificate=Certificate
+apps.saml.metaFile=Metadata
 apps.saml.metadata.givenName=givenName
 apps.saml.issuer=Issuer
 apps.saml.nameIdConvert.upperCase=upperCase
 apps.saml.metadata.orgURL=orgURL
 apps.saml.metadata.info=SAML V2.0 Info
 apps.saml.certSubject=certSubject
-apps.saml.certMetaFile=certMetaFile
 apps.saml.encrypted.no=No encrypted
 apps.saml.binding=Binding
 apps.saml.metadata.surName=surName

+ 3 - 2
maxkey-web-manage/src/main/resources/messages/message_zh_CN.properties

@@ -362,15 +362,16 @@ apps.saml.fileType=\u8bc1\u4e66\u7c7b\u578b
 apps.saml.nameIdConvert=NameId Convert
 apps.saml.target=\u76ee\u6807\u5730\u5740
 apps.saml.metadata.telephoneNumber=\u7535\u8bdd\u53f7\u7801
-apps.saml.fileType.metadata=SAML\u5143\u6570\u636e
+apps.saml.fileType.metadata.file=SAML\u5143\u6570\u636e\u6587\u4ef6
+apps.saml.fileType.metadata.url=SAML\u5143\u6570\u636e\u5730\u5740
 apps.saml.fileType.certificate=\u8bc1\u4e66
+apps.saml.metaFile=SAML\u5143\u6570\u636e
 apps.saml.metadata.givenName=\u540d
 apps.saml.issuer=Issuer
 apps.saml.nameIdConvert.upperCase=\u5927\u5199
 apps.saml.metadata.orgURL=\u7ec4\u7ec7\u7ad9\u70b9
 apps.saml.metadata.info=SAML V2.0 \u5143\u6570\u636e\u914d\u7f6e
 apps.saml.certSubject=\u8bc1\u4e66\u4e3b\u9898
-apps.saml.certMetaFile=\u8bc1\u4e66\u6587\u4ef6
 apps.saml.encrypted.no=\u4e0d\u52a0\u5bc6
 apps.saml.binding=Binding
 apps.saml.metadata.surName=\u59d3

+ 28 - 11
maxkey-web-manage/src/main/resources/templates/views/apps/saml20/appAdd.ftl

@@ -4,6 +4,22 @@
 	<#include  "../../layout/header.ftl"/>
 	<#include  "../../layout/common.cssjs.ftl"/>
 	<#include  "../appCommonHead.ftl"/>
+	<script type="text/javascript">
+		<!--
+		$(function(){	
+			$("#fileType").change(function(){
+				if($("#fileType").val() !="metadata_url"){
+					$(".MetaFile").show();
+					$(".MetaUrl").hide();
+				}else{
+					$(".MetaFile").hide();
+					$(".MetaUrl").show();
+				}
+			}); 
+	});
+	//-->
+	</script>
+	
 </head>
 <body>
 <form id="actionForm_app"  method="post" type="label" autoclose="true"   closeWindow="true" 
@@ -29,23 +45,23 @@
 				<tr>
                     <th><@locale code="apps.saml.spAcsUrl" />:</th>
                     <td colspan =3>
-                        <input type="text" class="form-control"   id="spAcsUrl" name="spAcsUrl"  title="" value=""  required="" />
+                        <input type="text" class="form-control"   id="spAcsUrl" name="spAcsUrl"  title="" value=""   />
                     </td>
                 </tr>
 				<tr>
 					<th><@locale code="apps.saml.entityId" />:</th>
 					<td colspan =3>
-						<input type="text" class="form-control"   id="entityId" name="entityId"  title="" value=""  required="" />
+						<input type="text" class="form-control"   id="entityId" name="entityId"  title="" value=""  />
 					</td>
 				</tr>
 				<tr>
 					<th><@locale code="apps.saml.issuer" />:</th>
 					<td>
-						<input type="text" class="form-control"   id="issuer" name="issuer"  title="" value=""  required="" />
+						<input type="text" class="form-control"   id="issuer" name="issuer"  title="" value=""   />
 					</td>
 					<th><@locale code="apps.saml.audience" />:</th>
                     <td >
-                        <input type="text" class="form-control"   id="audience" name="audience"  title="" value="" required="" />
+                        <input type="text" class="form-control"   id="audience" name="audience"  title="" value=""  />
                     </td>
 				</tr>
 				<tr>
@@ -137,19 +153,20 @@
 					<td>
 						<select  id="fileType" name="fileType"  class="form-control"  >
 							<option value="certificate"><@locale code="apps.saml.fileType.certificate" /></option>
-							<option value="metadata"  selected><@locale code="apps.saml.fileType.metadata" /></option>
+							<option value="metadata_file"  selected><@locale code="apps.saml.fileType.metadata.file" /></option>
+							<option value="metadata_url"           ><@locale code="apps.saml.fileType.metadata.url" /></option>
 						</select>
 						<b class="orange">*</b><label for="fileType"></label>
 					</td>
-					<th><@locale code="apps.saml.certMetaFile" />:</th>
+					<th><@locale code="apps.saml.metaFile" />:</th>
 					<td nowrap >
-						<div style="float: left;">
-							<img id="certMetaFileImg"  height="40" width="80" alt="upload certificate or metadata file" src="<@base />/static/images/cert.png">
+						<div class="MetaFile" style="float: left;">
+							<img id="metaFileImg"  height="40" width="80" alt="upload certificate or metadata file" src="<@base />/static/images/cert.png">
 						</div>
-						<div style="float: left; width: 250px;">
-							<input class="form-control"   id="certMetaFile" type="file" name="certMetaFile" />
-							<b class="orange">*</b><label for="certMetaFile"></label>
+						<div class="MetaFile" style="float: left; width: 250px;">
+							<input class="form-control"   id="metaFile" type="file" name="metaFile" />
 						</div>
+						<input type="text" style="display:none" class="form-control MetaUrl"   id="metaUrl" name="metaUrl"  title="" value=""   />
 					</td>
 				</tr>
 				

+ 23 - 15
maxkey-web-manage/src/main/resources/templates/views/apps/saml20/appUpdate.ftl

@@ -7,14 +7,16 @@
 	<#setting number_format="#">
 	<script type="text/javascript">
 	<!--
-	$(function(){	
-		$("#certMetaFileImg").on("click",function(){
-			if(!$("#certMetaFileImg").hasClass("appended")){
-				$("#certMetaFileImg").after('<input id="certMetaFile" type="file" name="certMetaFile" />');
-				$("#certMetaFileImg").addClass("appended");
+	$(function(){			
+		$("#fileType").change(function(){
+			if($("#fileType").val() !="metadata_url"){
+				$(".MetaFile").show();
+				$(".MetaUrl").hide();
+			}else{
+				$(".MetaFile").hide();
+				$(".MetaUrl").show();
 			}
-			
-		});
+		}); 
 	});
 	//-->
 	</script>
@@ -43,13 +45,13 @@
 				<tr>
                     <th><@locale code="apps.saml.spAcsUrl" />:</th>
                     <td colspan =3>
-                        <input type="text" class="form-control"  id="spAcsUrl" name="spAcsUrl"  title="" value="${model.spAcsUrl!}"  required="" />
+                        <input type="text" class="form-control"  id="spAcsUrl" name="spAcsUrl"  title="" value="${model.spAcsUrl!}"   />
                     </td>
                 </tr>
 				<tr>
 					<th><@locale code="apps.saml.entityId" />:</th>
 					<td >
-						<input type="text" class="form-control"  id="entityId" name="entityId"  title="" value="${model.entityId!}"  required="" />
+						<input type="text" class="form-control"  id="entityId" name="entityId"  title="" value="${model.entityId!}"  />
 					</td>
 					<td></td>
                     <td  >
@@ -59,11 +61,11 @@
 				<tr>
 					<th><@locale code="apps.saml.issuer" />:</th>
 					<td >
-						<input type="text" class="form-control"  id="issuer" name="issuer"  title="" value="${model.issuer!}"  required="" />
+						<input type="text" class="form-control"  id="issuer" name="issuer"  title="" value="${model.issuer!}"  />
 					</td>
 					<th><@locale code="apps.saml.audience" />:</th>
                     <td  colspan =2>
-                        <input type="text" class="form-control"  id="audience" name="audience"  title="" value="${model.audience!}"  required="" />
+                        <input type="text" class="form-control"  id="audience" name="audience"  title="" value="${model.audience!}"   />
                     </td>
 				</tr>
 				<tr>
@@ -152,13 +154,19 @@
 					<td>
 						<select  id="fileType" name="fileType"  class="form-control" >
 							<option value="certificate" selected><@locale code="apps.saml.fileType.certificate" /></option>
-							<option value="metadata"><@locale code="apps.saml.fileType.metadata" /></option>
+							<option value="metadata_file"><@locale code="apps.saml.fileType.metadata.file" /></option>
+							<option value="metadata_url" ><@locale code="apps.saml.fileType.metadata.url" /></option>
 						</select>
 					</td>
-					<th><@locale code="apps.saml.certMetaFile" />:</th>
+					<th><@locale code="apps.saml.metaFile" />:</th>
 					<td>
-						<img id="certMetaFileImg"  height="40" width="80" alt="upload certificate or metadata file" src="<@base />/static/images/cert.png">
-						<b class="orange">*</b><label for="certMetaFile"></label>
+						<div class="MetaFile" style="float: left;">
+							<img id="metaFileImg"  height="40" width="80" alt="upload certificate or metadata file" src="<@base />/static/images/cert.png">
+						</div>
+						<div class="MetaFile" style="float: left; width: 250px;">
+							<input class="form-control"   id="metaFile" type="file" name="metaFile" />
+						</div>
+						<input type="text" style="display:none" class="form-control MetaUrl"   id="metaUrl" name="metaUrl"  title="" value="${model.metaUrl!}"   />
 					</td>
 				</tr>
 				

Разлика између датотеке није приказан због своје велике величине
+ 100 - 0
sql/maxkey_v2.4.0.RC1.sql


Неке датотеке нису приказане због велике количине промена