dashboard/edit/auth/azuread.vue

264 lines
8.3 KiB
Vue

<script>
import Loading from '@/components/Loading';
import CreateEditView from '@/mixins/create-edit-view';
import CruResource from '@/components/CruResource';
import InfoBox from '@/components/InfoBox';
import RadioGroup from '@/components/form/RadioGroup';
import LabeledInput from '@/components/form/LabeledInput';
import Banner from '@/components/Banner';
import AuthBanner from '@/components/auth/AuthBanner';
import CopyToClipboardText from '@/components/CopyToClipboardText.vue';
import AllowedPrincipals from '@/components/auth/AllowedPrincipals';
import AuthConfig from '@/mixins/auth-config';
const TENANT_ID_TOKEN = '__[[TENANT_ID]]__';
const ENDPOINT_MAPPING = {
standard: {
endpoint: 'https://login.microsoftonline.com/',
graphEndpoint: 'https://graph.windows.net/',
tokenEndpoint: `https://login.microsoftonline.com/${ TENANT_ID_TOKEN }/oauth2/token`,
authEndpoint: `https://login.microsoftonline.com/${ TENANT_ID_TOKEN }/oauth2/authorize`,
},
china: {
endpoint: 'https://login.chinacloudapi.cn/',
graphEndpoint: 'https://graph.chinacloudapi.cn/',
tokenEndpoint: `https://login.chinacloudapi.cn/${ TENANT_ID_TOKEN }/oauth2/token`,
authEndpoint: `https://login.chinacloudapi.cn/${ TENANT_ID_TOKEN }/oauth2/authorize`,
},
custom: {
endpoint: 'https://login.microsoftonline.com/',
graphEndpoint: '',
tokenEndpoint: '',
authEndpoint: '',
}
};
export default {
components: {
Loading,
CruResource,
InfoBox,
RadioGroup,
LabeledInput,
Banner,
CopyToClipboardText,
AllowedPrincipals,
AuthBanner
},
mixins: [CreateEditView, AuthConfig],
async fetch() {
await this.reloadModel();
},
data() {
return {
endpoint: 'standard',
// Storing the applicationSecret is necessary because norman doesn't support returning secrets and when we
// override the steve authconfig with a norman config the applicationSecret is lost
applicationSecret: this.value.applicationSecret
};
},
computed: {
tArgs() {
return {
baseUrl: this.baseUrl,
provider: this.displayName,
username: this.principal.loginName || this.principal.name,
};
},
replyUrl() {
return `${ window.location.origin }/verify-auth-azure/dashboard/auth/verify`;
},
tenantId() {
return this.model?.tenantId;
},
toSave() {
this.$set(this.model, 'applicationSecret', this.model.applicationSecret || this.applicationSecret);
return {
config: {
...this.model,
applicationSecret: this.model.applicationSecret || this.applicationSecret,
enabled: true,
description: 'Enable AzureAD'
}
};
},
},
watch: {
endpoint(value) {
this.setEndpoints(value);
},
tenantId() {
if (this.endpoint !== 'custom') {
this.setEndpoints(this.endpoint);
}
},
model: {
deep: true,
handler() {
this.model.accessMode = this.model.accessMode || 'unrestricted';
this.model.rancherUrl = this.model.rancherUrl || this.replyUrl;
if (this.endpoint !== 'custom') {
this.setEndpoints(this.endpoint);
}
if (this.model.applicationSecret) {
this.$set(this, 'applicationSecret', this.model.applicationSecret);
}
}
}
},
methods: {
setEndpoints(endpoint) {
Object.keys(ENDPOINT_MAPPING[endpoint]).forEach((key) => {
this.$set(this.model, key, ENDPOINT_MAPPING[endpoint][key].replace(TENANT_ID_TOKEN, this.model.tenantId));
});
},
},
};
</script>
<template>
<Loading v-if="$fetchState.pending" />
<div v-else>
<CruResource
:done-route="doneRoute"
:mode="mode"
:resource="model"
:subtypes="[]"
:validation-passed="true"
:finish-button-mode="model.enabled ? 'edit' : 'enable'"
:can-yaml="false"
:errors="errors"
:show-cancel="showCancel"
:cancel-event="true"
@error="e=>errors = e"
@finish="save"
@cancel="cancel"
>
<template v-if="model.enabled && !isEnabling && !editConfig">
<AuthBanner :t-args="tArgs" :disable="disable" :edit="goToEdit">
<template slot="rows">
<tr><td>{{ t(`authConfig.azuread.tenantId`) }}: </td><td>{{ model.tenantId }}</td></tr>
<tr><td>{{ t(`authConfig.azuread.applicationId`) }}: </td><td>{{ model.applicationId }}</td></tr>
<tr><td>{{ t(`authConfig.azuread.endpoint`) }}: </td><td>{{ model.endpoint }}</td></tr>
<tr><td>{{ t(`authConfig.azuread.graphEndpoint`) }}: </td><td>{{ model.graphEndpoint }}</td></tr>
<tr><td>{{ t(`authConfig.azuread.tokenEndpoint`) }}: </td><td>{{ model.tokenEndpoint }}</td></tr>
<tr><td>{{ t(`authConfig.azuread.authEndpoint`) }}: </td><td>{{ model.authEndpoint }}</td></tr>
</template>
</AuthBanner>
<hr />
<AllowedPrincipals provider="azuread" :auth-config="model" :mode="mode" />
</template>
<template v-else>
<Banner v-if="!model.enabled" :label="t('authConfig.stateBanner.disabled', tArgs)" color="warning" />
<InfoBox v-if="!model.enabled" class="mt-20 mb-20 p-10">
Azure AD requires a whitelisted URL for your Rancher server before beginning this setup. Please ensure that the following URL is set in the Reply URL section of your Azure Portal. Please note that is may take up to 5 minutes for the whitelisted URL to propagate.
<br />
<label>Reply URL: </label> <CopyToClipboardText :text="replyUrl" />
</InfoBox>
<div class="row mb-20">
<div class="col span-6">
<LabeledInput
id="tenant-id"
v-model="model.tenantId"
label="Tenant ID"
:mode="mode"
:required="true"
tooltip="From the Azure AD portal"
placeholder="A long UUID string"
/>
</div>
</div>
<div class="row mb-20">
<div class="col span-6">
<LabeledInput
id="application-id"
v-model="model.applicationId"
label="Application ID"
:mode="mode"
:required="true"
placeholder="A long UUID string"
/>
</div>
<div class="col span-6">
<LabeledInput
id="application-secret"
v-model="model.applicationSecret"
type="password"
label="Application Secret"
:required="true"
:mode="mode"
/>
</div>
</div>
<RadioGroup
v-model="endpoint"
class="mb-20"
:required="true"
label="Endpoints"
name="endpoints"
:options="['standard','china', 'custom']"
:mode="mode"
:labels="['Standard', 'China', 'Custom']"
/>
<div v-if="endpoint === 'custom'">
<div class="row mb-20">
<div class="col span-6">
<LabeledInput
v-model="model.endpoint"
label="Endpoint"
:mode="mode"
:required="true"
/>
</div>
<div class="col span-6">
<LabeledInput
v-model="model.graphEndpoint"
label="Graph Endpoint"
:required="true"
:mode="mode"
/>
</div>
</div>
<div class="row mb-20">
<div class="col span-6">
<LabeledInput
v-model="model.tokenEndpoint"
label="Token Endpoint"
:mode="mode"
:required="true"
/>
</div>
<div class="col span-6">
<LabeledInput
v-model="model.authEndpoint"
label="Auth Endpoint"
:required="true"
:mode="mode"
/>
</div>
</div>
</div>
</template>
</CruResource>
</div>
</template>