feat: support SAML and test with aliyun IDaaS (#346)

* feat: support SAML and test with aliyun IDaaS

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* refactor: refactor saml.go and router

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* fix: add param to getSamlLogin()

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* feat: add inputs to parse metadata automatically and show sp-acs-url, sp-entity-id

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
This commit is contained in:
Yixiang Zhao
2021-12-06 21:46:50 +08:00
committed by GitHub
parent 667158f585
commit 113398c36b
17 changed files with 444 additions and 47 deletions

View File

@ -18,6 +18,8 @@ import {LinkOutlined} from "@ant-design/icons";
import * as ProviderBackend from "./backend/ProviderBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import { authConfig } from "./auth/Auth";
import copy from 'copy-to-clipboard';
const { Option } = Select;
const { TextArea } = Input;
@ -103,6 +105,10 @@ class ProviderEditPage extends React.Component {
{id: 'Tencent Cloud COS', name: 'Tencent Cloud COS'},
]
);
} else if (provider.category === "SAML") {
return ([
{id: 'Aliyun IDaaS', name: 'Aliyun IDaaS'},
]);
} else {
return [];
}
@ -156,6 +162,17 @@ class ProviderEditPage extends React.Component {
</Row>;
}
loadSamlConfiguration() {
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(this.state.provider.metadata, "text/xml");
var cert = xmlDoc.getElementsByTagName("ds:X509Certificate")[0].childNodes[0].nodeValue;
var endpoint = xmlDoc.getElementsByTagName("md:SingleSignOnService")[0].getAttribute("Location");
var issuerUrl = xmlDoc.getElementsByTagName("md:EntityDescriptor")[0].getAttribute("entityID");
this.updateProviderField("idP", cert);
this.updateProviderField("endpoint", endpoint);
this.updateProviderField("issuerUrl", issuerUrl);
}
renderProvider() {
return (
<Card size="small" title={
@ -202,6 +219,8 @@ class ProviderEditPage extends React.Component {
} else if (value === "Storage") {
this.updateProviderField('type', 'Local File System');
this.updateProviderField('domain', Setting.getFullServerUrl());
} else if (value === "SAML") {
this.updateProviderField('type', 'Aliyun IDaaS');
}
})}>
{
@ -210,6 +229,7 @@ class ProviderEditPage extends React.Component {
{id: 'Email', name: 'Email'},
{id: 'SMS', name: 'SMS'},
{id: 'Storage', name: 'Storage'},
{id: 'SAML', name: 'SAML'},
].map((providerCategory, index) => <Option key={index} value={providerCategory.id}>{providerCategory.name}</Option>)
}
</Select>
@ -391,6 +411,96 @@ class ProviderEditPage extends React.Component {
</Col>
</Row>
</React.Fragment>
) : this.state.provider.category === "SAML" ? (
<React.Fragment>
<Row style={{marginTop: '20px'}} >
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Metadata"), i18next.t("provider:Metadata - Tooltip"))} :
</Col>
<Col span={22}>
<TextArea rows={4} value={this.state.provider.metadata} onChange={e => {
this.updateProviderField('metadata', e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: '20px'}}>
<Col style={{marginTop: '5px'}} span={2}></Col>
<Col span={2}>
<Button type="primary" onClick={() => {
try {
this.loadSamlConfiguration();
Setting.showMessage("success", i18next.t("provider:Parse Metadata successfully"));
} catch (err) {
Setting.showMessage("error", i18next.t("provider:Can not parse Metadata"));
}
}}>
{i18next.t("provider:Parse")}
</Button>
</Col>
</Row>
<Row style={{marginTop: '20px'}} >
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Endpoint"), i18next.t("provider:SAML 2.0 Endpoint (HTTP)"))} :
</Col>
<Col span={22} >
<Input value={this.state.provider.endpoint} onChange={e => {
this.updateProviderField('endpoint', e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: '20px'}} >
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:IdP"), i18next.t("provider:IdP public key"))} :
</Col>
<Col span={22} >
<Input value={this.state.provider.idP} onChange={e => {
this.updateProviderField('idP', e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: '20px'}} >
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Issuer URL"), i18next.t("provider:Issuer URL - Tooltip"))} :
</Col>
<Col span={22} >
<Input value={this.state.provider.issuerUrl} onChange={e => {
this.updateProviderField('issuerUrl', e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: '20px'}} >
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:SP ACS URL"), i18next.t("provider:SP ACS URL - Tooltip"))} :
</Col>
<Col span={21} >
<Input value={`${authConfig.serverUrl}/api/acs`} readOnly="readonly" />
</Col>
<Col span={1}>
<Button type="primary" onClick={() => {
copy(`${authConfig.serverUrl}/api/acs`);
Setting.showMessage("success", i18next.t("provider:Link copied to clipboard successfully"));
}}>
{i18next.t("provider:Copy")}
</Button>
</Col>
</Row>
<Row style={{marginTop: '20px'}} >
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:SP Entity ID"), i18next.t("provider:SP ACS URL - Tooltip"))} :
</Col>
<Col span={21} >
<Input value={`${authConfig.serverUrl}/api/acs`} readOnly="readonly" />
</Col>
<Col span={1}>
<Button type="primary" onClick={() => {
copy(`${authConfig.serverUrl}/api/acs`);
Setting.showMessage("success", i18next.t("provider:Link copied to clipboard successfully"));
}}>
{i18next.t("provider:Copy")}
</Button>
</Col>
</Row>
</React.Fragment>
) : null
}
{this.getAppIdRow()}