提交 2f936c80 编写于 作者: MaxKey单点登录官方's avatar MaxKey单点登录官方

SAML Metadata URL配置读取

上级 16cba997
......@@ -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
......
......@@ -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;
}
......
......@@ -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=");
......
......@@ -19,6 +19,7 @@
SVD.NAMEIDCONVERT,
SVD.SIGNATURE,
SVD.DIGESTMETHOD,
SVD.METAURL,
APP.*
FROM
MXK_APPS_SAML_V20_DETAILS SVD,
......
......@@ -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;
}
}
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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>
......
......@@ -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>
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册