web/admin: migrate provider forms
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		
							
								
								
									
										24
									
								
								swagger.yaml
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								swagger.yaml
									
									
									
									
									
								
							| @ -14652,7 +14652,6 @@ definitions: | |||||||
|   Provider: |   Provider: | ||||||
|     required: |     required: | ||||||
|       - name |       - name | ||||||
|       - application |  | ||||||
|       - authorization_flow |       - authorization_flow | ||||||
|     type: object |     type: object | ||||||
|     properties: |     properties: | ||||||
| @ -14664,9 +14663,6 @@ definitions: | |||||||
|         title: Name |         title: Name | ||||||
|         type: string |         type: string | ||||||
|         minLength: 1 |         minLength: 1 | ||||||
|       application: |  | ||||||
|         title: Application |  | ||||||
|         type: string |  | ||||||
|       authorization_flow: |       authorization_flow: | ||||||
|         title: Authorization flow |         title: Authorization flow | ||||||
|         description: Flow used when authorizing this provider. |         description: Flow used when authorizing this provider. | ||||||
| @ -15456,7 +15452,6 @@ definitions: | |||||||
|   OAuth2Provider: |   OAuth2Provider: | ||||||
|     required: |     required: | ||||||
|       - name |       - name | ||||||
|       - application |  | ||||||
|       - authorization_flow |       - authorization_flow | ||||||
|     type: object |     type: object | ||||||
|     properties: |     properties: | ||||||
| @ -15468,9 +15463,6 @@ definitions: | |||||||
|         title: Name |         title: Name | ||||||
|         type: string |         type: string | ||||||
|         minLength: 1 |         minLength: 1 | ||||||
|       application: |  | ||||||
|         title: Application |  | ||||||
|         type: string |  | ||||||
|       authorization_flow: |       authorization_flow: | ||||||
|         title: Authorization flow |         title: Authorization flow | ||||||
|         description: Flow used when authorizing this provider. |         description: Flow used when authorizing this provider. | ||||||
| @ -16686,7 +16678,6 @@ definitions: | |||||||
|   ProxyProvider: |   ProxyProvider: | ||||||
|     required: |     required: | ||||||
|       - name |       - name | ||||||
|       - application |  | ||||||
|       - authorization_flow |       - authorization_flow | ||||||
|       - internal_host |       - internal_host | ||||||
|       - external_host |       - external_host | ||||||
| @ -16700,9 +16691,6 @@ definitions: | |||||||
|         title: Name |         title: Name | ||||||
|         type: string |         type: string | ||||||
|         minLength: 1 |         minLength: 1 | ||||||
|       application: |  | ||||||
|         title: Application |  | ||||||
|         type: string |  | ||||||
|       authorization_flow: |       authorization_flow: | ||||||
|         title: Authorization flow |         title: Authorization flow | ||||||
|         description: Flow used when authorizing this provider. |         description: Flow used when authorizing this provider. | ||||||
| @ -16774,7 +16762,6 @@ definitions: | |||||||
|   SAMLProvider: |   SAMLProvider: | ||||||
|     required: |     required: | ||||||
|       - name |       - name | ||||||
|       - application |  | ||||||
|       - authorization_flow |       - authorization_flow | ||||||
|       - acs_url |       - acs_url | ||||||
|     type: object |     type: object | ||||||
| @ -16787,9 +16774,6 @@ definitions: | |||||||
|         title: Name |         title: Name | ||||||
|         type: string |         type: string | ||||||
|         minLength: 1 |         minLength: 1 | ||||||
|       application: |  | ||||||
|         title: Application |  | ||||||
|         type: string |  | ||||||
|       authorization_flow: |       authorization_flow: | ||||||
|         title: Authorization flow |         title: Authorization flow | ||||||
|         description: Flow used when authorizing this provider. |         description: Flow used when authorizing this provider. | ||||||
| @ -16892,6 +16876,14 @@ definitions: | |||||||
|         type: string |         type: string | ||||||
|         format: uuid |         format: uuid | ||||||
|         x-nullable: true |         x-nullable: true | ||||||
|  |       sp_binding: | ||||||
|  |         title: Service Provider Binding | ||||||
|  |         description: This determines how authentik sends the response back to the | ||||||
|  |           Service Provider. | ||||||
|  |         type: string | ||||||
|  |         enum: | ||||||
|  |           - redirect | ||||||
|  |           - post | ||||||
|   SAMLMetadata: |   SAMLMetadata: | ||||||
|     type: object |     type: object | ||||||
|     properties: |     properties: | ||||||
|  | |||||||
| @ -4,10 +4,6 @@ export class AdminURLManager { | |||||||
|         return `/administration/policies/${rest}`; |         return `/administration/policies/${rest}`; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static providers(rest: string): string { |  | ||||||
|         return `/administration/providers/${rest}`; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static stages(rest: string): string { |     static stages(rest: string): string { | ||||||
|         return `/administration/stages/${rest}`; |         return `/administration/stages/${rest}`; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -72,12 +72,14 @@ export class GroupForm extends Form<Group> { | |||||||
|                 ?required=${true} |                 ?required=${true} | ||||||
|                 name="users"> |                 name="users"> | ||||||
|                 <select class="pf-c-form-control" multiple> |                 <select class="pf-c-form-control" multiple> | ||||||
|                     ${until(new CoreApi(DEFAULT_CONFIG).coreUsersList({}).then(users => { |                     ${until(new CoreApi(DEFAULT_CONFIG).coreUsersList({ | ||||||
|  |                         ordering: "username", | ||||||
|  |                     }).then(users => { | ||||||
|                         return users.results.map(user => { |                         return users.results.map(user => { | ||||||
|                             const selected = Array.from(this.group?.users || []).some(su => { |                             const selected = Array.from(this.group?.users || []).some(su => { | ||||||
|                                 return su == user.pk; |                                 return su == user.pk; | ||||||
|                             }); |                             }); | ||||||
|                             return html`<option value=${ifDefined(user.pk)} ?selected=${selected}>${user.username}</option>`; |                             return html`<option value=${ifDefined(user.pk)} ?selected=${selected}>${user.username} (${user.name})</option>`; | ||||||
|                         }); |                         }); | ||||||
|                     }))} |                     }))} | ||||||
|                 </select> |                 </select> | ||||||
|  | |||||||
| @ -77,10 +77,7 @@ export class ServiceConnectionDockerForm extends Form<DockerServiceConnection> { | |||||||
|                         ordering: "pk" |                         ordering: "pk" | ||||||
|                     }).then(certs => { |                     }).then(certs => { | ||||||
|                         return certs.results.map(cert => { |                         return certs.results.map(cert => { | ||||||
|                             const selected = Array.from(this.sc?.tlsVerification || []).some(sp => { |                             return html`<option value=${ifDefined(cert.pk)} ?selected=${this.sc?.tlsVerification === cert.pk}>${cert.name}</option>`; | ||||||
|                                 return sp == cert.pk; |  | ||||||
|                             }); |  | ||||||
|                             return html`<option value=${ifDefined(cert.pk)} ?selected=${selected}>${cert.name}</option>`; |  | ||||||
|                         }); |                         }); | ||||||
|                     }))} |                     }))} | ||||||
|                 </select> |                 </select> | ||||||
| @ -96,10 +93,7 @@ export class ServiceConnectionDockerForm extends Form<DockerServiceConnection> { | |||||||
|                         ordering: "pk" |                         ordering: "pk" | ||||||
|                     }).then(certs => { |                     }).then(certs => { | ||||||
|                         return certs.results.map(cert => { |                         return certs.results.map(cert => { | ||||||
|                             const selected = Array.from(this.sc?.tlsAuthentication || []).some(sp => { |                             return html`<option value=${ifDefined(cert.pk)} ?selected=${this.sc?.tlsAuthentication === cert.pk}>${cert.name}</option>`; | ||||||
|                                 return sp == cert.pk; |  | ||||||
|                             }); |  | ||||||
|                             return html`<option value=${ifDefined(cert.pk)} ?selected=${selected}>${cert.name}</option>`; |  | ||||||
|                         }); |                         }); | ||||||
|                     }))} |                     }))} | ||||||
|                 </select> |                 </select> | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import { DEFAULT_CONFIG } from "../../api/Config"; | |||||||
| import { Form } from "../../elements/forms/Form"; | import { Form } from "../../elements/forms/Form"; | ||||||
| import { ifDefined } from "lit-html/directives/if-defined"; | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
| import "../../elements/forms/HorizontalFormElement"; | import "../../elements/forms/HorizontalFormElement"; | ||||||
|  | import "../../elements/CodeMirror"; | ||||||
|  |  | ||||||
| @customElement("ak-property-mapping-ldap-form") | @customElement("ak-property-mapping-ldap-form") | ||||||
| export class PropertyMappingLDAPForm extends Form<LDAPPropertyMapping> { | export class PropertyMappingLDAPForm extends Form<LDAPPropertyMapping> { | ||||||
| @ -60,7 +61,7 @@ export class PropertyMappingLDAPForm extends Form<LDAPPropertyMapping> { | |||||||
|             <ak-form-element-horizontal |             <ak-form-element-horizontal | ||||||
|                 label=${gettext("Expression")} |                 label=${gettext("Expression")} | ||||||
|                 name="expression"> |                 name="expression"> | ||||||
|                 <ak-codemirror mode="python" value="${this.mapping?.expression}"> |                 <ak-codemirror mode="python" value="${ifDefined(this.mapping?.expression)}"> | ||||||
|                 </ak-codemirror> |                 </ak-codemirror> | ||||||
|                 <p class="pf-c-form__helper-text"> |                 <p class="pf-c-form__helper-text"> | ||||||
|                     Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables. |                     Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables. | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import { DEFAULT_CONFIG } from "../../api/Config"; | |||||||
| import { Form } from "../../elements/forms/Form"; | import { Form } from "../../elements/forms/Form"; | ||||||
| import { ifDefined } from "lit-html/directives/if-defined"; | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
| import "../../elements/forms/HorizontalFormElement"; | import "../../elements/forms/HorizontalFormElement"; | ||||||
|  | import "../../elements/CodeMirror"; | ||||||
|  |  | ||||||
| @customElement("ak-property-mapping-saml-form") | @customElement("ak-property-mapping-saml-form") | ||||||
| export class PropertyMappingLDAPForm extends Form<SAMLPropertyMapping> { | export class PropertyMappingLDAPForm extends Form<SAMLPropertyMapping> { | ||||||
| @ -62,7 +63,7 @@ export class PropertyMappingLDAPForm extends Form<SAMLPropertyMapping> { | |||||||
|             <ak-form-element-horizontal |             <ak-form-element-horizontal | ||||||
|                 label=${gettext("Friendly Name")} |                 label=${gettext("Friendly Name")} | ||||||
|                 name="friendlyName"> |                 name="friendlyName"> | ||||||
|                 <input type="text" value="${ifDefined(this.mapping?.friendlyName)}" class="pf-c-form-control"> |                 <input type="text" value="${ifDefined(this.mapping?.friendlyName || "")}" class="pf-c-form-control"> | ||||||
|                 <p class="pf-c-form__helper-text"> |                 <p class="pf-c-form__helper-text"> | ||||||
|                     ${gettext("Optionally set the `FriendlyName` value of the Assertion attribute.")} |                     ${gettext("Optionally set the `FriendlyName` value of the Assertion attribute.")} | ||||||
|                 </p> |                 </p> | ||||||
| @ -70,7 +71,7 @@ export class PropertyMappingLDAPForm extends Form<SAMLPropertyMapping> { | |||||||
|             <ak-form-element-horizontal |             <ak-form-element-horizontal | ||||||
|                 label=${gettext("Expression")} |                 label=${gettext("Expression")} | ||||||
|                 name="expression"> |                 name="expression"> | ||||||
|                 <ak-codemirror mode="python" value="${this.mapping?.expression}"> |                 <ak-codemirror mode="python" value="${ifDefined(this.mapping?.expression)}"> | ||||||
|                 </ak-codemirror> |                 </ak-codemirror> | ||||||
|                 <p class="pf-c-form__helper-text"> |                 <p class="pf-c-form__helper-text"> | ||||||
|                     Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables. |                     Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables. | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import { DEFAULT_CONFIG } from "../../api/Config"; | |||||||
| import { Form } from "../../elements/forms/Form"; | import { Form } from "../../elements/forms/Form"; | ||||||
| import { ifDefined } from "lit-html/directives/if-defined"; | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
| import "../../elements/forms/HorizontalFormElement"; | import "../../elements/forms/HorizontalFormElement"; | ||||||
|  | import "../../elements/CodeMirror"; | ||||||
|  |  | ||||||
| @customElement("ak-property-mapping-scope-form") | @customElement("ak-property-mapping-scope-form") | ||||||
| export class PropertyMappingScopeForm extends Form<ScopeMapping> { | export class PropertyMappingScopeForm extends Form<ScopeMapping> { | ||||||
| @ -67,7 +68,7 @@ export class PropertyMappingScopeForm extends Form<ScopeMapping> { | |||||||
|             <ak-form-element-horizontal |             <ak-form-element-horizontal | ||||||
|                 label=${gettext("Expression")} |                 label=${gettext("Expression")} | ||||||
|                 name="expression"> |                 name="expression"> | ||||||
|                 <ak-codemirror mode="python" value="${this.mapping?.expression}"> |                 <ak-codemirror mode="python" value="${ifDefined(this.mapping?.expression)}"> | ||||||
|                 </ak-codemirror> |                 </ak-codemirror> | ||||||
|                 <p class="pf-c-form__helper-text"> |                 <p class="pf-c-form__helper-text"> | ||||||
|                     Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables. |                     Expression using Python. See <a href="https://goauthentik.io/docs/property-mappings/expression/">here</a> for a list of all variables. | ||||||
|  | |||||||
| @ -3,16 +3,20 @@ import { customElement, html, property, TemplateResult } from "lit-element"; | |||||||
| import { AKResponse } from "../../api/Client"; | import { AKResponse } from "../../api/Client"; | ||||||
| import { TablePage } from "../../elements/table/TablePage"; | import { TablePage } from "../../elements/table/TablePage"; | ||||||
|  |  | ||||||
| import "../../elements/buttons/ModalButton"; |  | ||||||
| import "../../elements/buttons/SpinnerButton"; | import "../../elements/buttons/SpinnerButton"; | ||||||
| import "../../elements/buttons/Dropdown"; | import "../../elements/buttons/Dropdown"; | ||||||
| import "../../elements/forms/DeleteForm"; | import "../../elements/forms/DeleteForm"; | ||||||
|  | import "../../elements/forms/ModalForm"; | ||||||
|  | import "../../elements/forms/ProxyForm"; | ||||||
|  | import "./oauth2/OAuth2ProviderForm"; | ||||||
|  | import "./proxy/ProxyProviderForm"; | ||||||
|  | import "./saml/SAMLProviderForm"; | ||||||
| import { TableColumn } from "../../elements/table/Table"; | import { TableColumn } from "../../elements/table/Table"; | ||||||
| import { until } from "lit-html/directives/until"; | import { until } from "lit-html/directives/until"; | ||||||
| import { PAGE_SIZE } from "../../constants"; | import { PAGE_SIZE } from "../../constants"; | ||||||
| import { Provider, ProvidersApi } from "authentik-api"; | import { Provider, ProvidersApi } from "authentik-api"; | ||||||
| import { DEFAULT_CONFIG } from "../../api/Config"; | import { DEFAULT_CONFIG } from "../../api/Config"; | ||||||
| import { AdminURLManager } from "../../api/legacy"; | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  |  | ||||||
| @customElement("ak-provider-list") | @customElement("ak-provider-list") | ||||||
| export class ProviderListPage extends TablePage<Provider> { | export class ProviderListPage extends TablePage<Provider> { | ||||||
| @ -63,12 +67,29 @@ export class ProviderListPage extends TablePage<Provider> { | |||||||
|                 ${gettext("Warning: Provider not assigned to any application.")}`, |                 ${gettext("Warning: Provider not assigned to any application.")}`, | ||||||
|             html`${item.verboseName}`, |             html`${item.verboseName}`, | ||||||
|             html` |             html` | ||||||
|             <ak-modal-button href="${AdminURLManager.providers(`${item.pk}/update/`)}"> |             <ak-forms-modal> | ||||||
|                 <ak-spinner-button slot="trigger" class="pf-m-secondary"> |                 <span slot="submit"> | ||||||
|  |                     ${gettext("Update")} | ||||||
|  |                 </span> | ||||||
|  |                 <span slot="header"> | ||||||
|  |                     ${gettext(`Update ${item.verboseName}`)} | ||||||
|  |                 </span> | ||||||
|  |                 <ak-proxy-form | ||||||
|  |                     slot="form" | ||||||
|  |                     .args=${{ | ||||||
|  |                         "providerUUID": item.pk | ||||||
|  |                     }} | ||||||
|  |                     type=${ifDefined(item.objectType)} | ||||||
|  |                     .typeMap=${{ | ||||||
|  |                         "oauth2": "ak-provider-oauth2-form", | ||||||
|  |                         "saml": "ak-provider-saml-form", | ||||||
|  |                         "proxy": "ak-provider-proxy-form", | ||||||
|  |                     }}> | ||||||
|  |                 </ak-proxy-form> | ||||||
|  |                 <button slot="trigger" class="pf-c-button pf-m-secondary"> | ||||||
|                     ${gettext("Edit")} |                     ${gettext("Edit")} | ||||||
|                 </ak-spinner-button> |                 </button> | ||||||
|                 <div slot="modal"></div> |             </ak-forms-modal> | ||||||
|             </ak-modal-button> |  | ||||||
|             <ak-forms-delete |             <ak-forms-delete | ||||||
|                 .obj=${item} |                 .obj=${item} | ||||||
|                 objectLabel=${gettext("Source")} |                 objectLabel=${gettext("Source")} | ||||||
| @ -95,12 +116,22 @@ export class ProviderListPage extends TablePage<Provider> { | |||||||
|                 ${until(new ProvidersApi(DEFAULT_CONFIG).providersAllTypes({}).then((types) => { |                 ${until(new ProvidersApi(DEFAULT_CONFIG).providersAllTypes({}).then((types) => { | ||||||
|                     return types.map((type) => { |                     return types.map((type) => { | ||||||
|                         return html`<li> |                         return html`<li> | ||||||
|                             <ak-modal-button href="${type.link}"> |                             <ak-forms-modal> | ||||||
|                                 <button slot="trigger" class="pf-c-dropdown__menu-item">${type.name}<br> |                                 <span slot="submit"> | ||||||
|  |                                     ${gettext("Create")} | ||||||
|  |                                 </span> | ||||||
|  |                                 <span slot="header"> | ||||||
|  |                                     ${gettext(`Create ${type.name}`)} | ||||||
|  |                                 </span> | ||||||
|  |                                 <ak-proxy-form | ||||||
|  |                                     slot="form" | ||||||
|  |                                     type=${type.link}> | ||||||
|  |                                 </ak-proxy-form> | ||||||
|  |                                 <button slot="trigger" class="pf-c-dropdown__menu-item"> | ||||||
|  |                                     ${type.name}<br> | ||||||
|                                     <small>${type.description}</small> |                                     <small>${type.description}</small> | ||||||
|                                 </button> |                                 </button> | ||||||
|                                 <div slot="modal"></div> |                             </ak-forms-modal> | ||||||
|                             </ak-modal-button> |  | ||||||
|                         </li>`; |                         </li>`; | ||||||
|                     }); |                     }); | ||||||
|                 }), html`<ak-spinner></ak-spinner>`)} |                 }), html`<ak-spinner></ak-spinner>`)} | ||||||
|  | |||||||
| @ -4,9 +4,9 @@ import "../../elements/buttons/ModalButton"; | |||||||
| import "../../elements/buttons/SpinnerButton"; | import "../../elements/buttons/SpinnerButton"; | ||||||
| import "../../elements/EmptyState"; | import "../../elements/EmptyState"; | ||||||
|  |  | ||||||
| import "./SAMLProviderViewPage"; | import "./saml/SAMLProviderViewPage"; | ||||||
| import "./OAuth2ProviderViewPage"; | import "./oauth2/OAuth2ProviderViewPage"; | ||||||
| import "./ProxyProviderViewPage"; | import "./proxy/ProxyProviderViewPage"; | ||||||
| import { Provider, ProvidersApi } from "authentik-api"; | import { Provider, ProvidersApi } from "authentik-api"; | ||||||
| import { DEFAULT_CONFIG } from "../../api/Config"; | import { DEFAULT_CONFIG } from "../../api/Config"; | ||||||
| import { ifDefined } from "lit-html/directives/if-defined"; | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  | |||||||
							
								
								
									
										206
									
								
								web/src/pages/providers/oauth2/OAuth2ProviderForm.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								web/src/pages/providers/oauth2/OAuth2ProviderForm.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,206 @@ | |||||||
|  | import { CryptoApi, FlowDesignationEnum, FlowsApi, OAuth2Provider, OAuth2ProviderClientTypeEnum, OAuth2ProviderIssuerModeEnum, OAuth2ProviderJwtAlgEnum, OAuth2ProviderSubModeEnum, PropertymappingsApi, ProvidersApi } from "authentik-api"; | ||||||
|  | import { gettext } from "django"; | ||||||
|  | import { customElement, property } from "lit-element"; | ||||||
|  | import { html, TemplateResult } from "lit-html"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import { Form } from "../../../elements/forms/Form"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  | import "../../../elements/forms/HorizontalFormElement"; | ||||||
|  |  | ||||||
|  | @customElement("ak-provider-oauth2-form") | ||||||
|  | export class OAuth2ProviderFormPage extends Form<OAuth2Provider> { | ||||||
|  |  | ||||||
|  |     set providerUUID(value: number) { | ||||||
|  |         new ProvidersApi(DEFAULT_CONFIG).providersOauth2Read({ | ||||||
|  |             id: value, | ||||||
|  |         }).then(provider => { | ||||||
|  |             this.provider = provider; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @property({attribute: false}) | ||||||
|  |     provider?: OAuth2Provider; | ||||||
|  |  | ||||||
|  |     getSuccessMessage(): string { | ||||||
|  |         if (this.provider) { | ||||||
|  |             return gettext("Successfully updated provider."); | ||||||
|  |         } else { | ||||||
|  |             return gettext("Successfully created provider."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send = (data: OAuth2Provider): Promise<OAuth2Provider> => { | ||||||
|  |         if (this.provider) { | ||||||
|  |             return new ProvidersApi(DEFAULT_CONFIG).providersOauth2Update({ | ||||||
|  |                 id: this.provider.pk || 0, | ||||||
|  |                 data: data | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             return new ProvidersApi(DEFAULT_CONFIG).providersOauth2Create({ | ||||||
|  |                 data: data | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     renderForm(): TemplateResult { | ||||||
|  |         return html`<form class="pf-c-form pf-m-horizontal"> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Name")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="name"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.name)}" class="pf-c-form-control" required> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Authorization flow")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="authorizationFlow"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     ${until(new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({ | ||||||
|  |                         ordering: "pk", | ||||||
|  |                         designation: FlowDesignationEnum.Authorization, | ||||||
|  |                     }).then(flows => { | ||||||
|  |                         return flows.results.map(flow => { | ||||||
|  |                             return html`<option value=${ifDefined(flow.pk)} ?selected=${this.provider?.authorizationFlow === flow.pk}>${flow.name}</option>`; | ||||||
|  |                         }); | ||||||
|  |                     }))} | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Flow used when authorizing this provider.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Client type")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="clientType"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value=${OAuth2ProviderClientTypeEnum.Confidential} ?selected=${this.provider?.clientType === OAuth2ProviderClientTypeEnum.Confidential}> | ||||||
|  |                         ${gettext("Confidential")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${OAuth2ProviderClientTypeEnum.Public} ?selected=${this.provider?.clientType === OAuth2ProviderClientTypeEnum.Public}> | ||||||
|  |                         ${gettext("Public")} | ||||||
|  |                     </option> | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Confidential clients are capable of maintaining the confidentiality of their credentials. Public clients are incapable.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Client ID")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="clientId"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.clientId)}" class="pf-c-form-control" required> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Client Secret")} | ||||||
|  |                 name="clientSecret"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.clientSecret /* TODO: Generate secret */)}" class="pf-c-form-control"> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Token validity")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="tokenValidity"> | ||||||
|  |                 <input type="text" value="${this.provider?.tokenValidity || "minutes=10"}" class="pf-c-form-control" required> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("JWT Algorithm")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="jwtAlg"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value=${OAuth2ProviderJwtAlgEnum.Rs256} ?selected=${this.provider?.jwtAlg === OAuth2ProviderJwtAlgEnum.Rs256}> | ||||||
|  |                         ${gettext("RS256 (Asymmetric Encryption)")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${OAuth2ProviderJwtAlgEnum.Hs256} ?selected=${this.provider?.jwtAlg === OAuth2ProviderJwtAlgEnum.Hs256}> | ||||||
|  |                         ${gettext("HS256 (Symmetric Encryption)")} | ||||||
|  |                     </option> | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Algorithm used to sign the JWT Tokens.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Scopes")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="propertyMappings"> | ||||||
|  |                 <select class="pf-c-form-control" multiple> | ||||||
|  |                     ${until(new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsScopeList({ | ||||||
|  |                         ordering: "scope_name" | ||||||
|  |                     }).then(scopes => { | ||||||
|  |                         return scopes.results.map(scope => { | ||||||
|  |                             const selected = Array.from(this.provider?.propertyMappings || []).some(su => { | ||||||
|  |                                 return su == scope.pk; | ||||||
|  |                             }); | ||||||
|  |                             return html`<option value=${ifDefined(scope.pk)} ?selected=${selected}>${scope.name}</option>`; | ||||||
|  |                         }); | ||||||
|  |                     }))} | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Select which scopes can be used by the client. The client stil has to specify the scope to access the data.")}</p> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Hold control/command to select multiple items.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("RSA Key")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="rsaKey"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     ${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({ | ||||||
|  |                         ordering: "pk", | ||||||
|  |                         hasKey: "true", | ||||||
|  |                     }).then(keys => { | ||||||
|  |                         return keys.results.map(key => { | ||||||
|  |                             return html`<option value=${ifDefined(key.pk)} ?selected=${this.provider?.rsaKey === key.pk}>${key.name}</option>`; | ||||||
|  |                         }); | ||||||
|  |                     }))} | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Key used to sign the tokens. Only required when JWT Algorithm is set to RS256.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Redirect URIs")} | ||||||
|  |                 name="redirectUris"> | ||||||
|  |                 <textarea class="pf-c-form-control">${this.provider?.redirectUris}</textarea> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Subject mode")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="subMode"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value="${OAuth2ProviderSubModeEnum.HashedUserId}" ?selected=${this.provider?.subMode === OAuth2ProviderSubModeEnum.HashedUserId}> | ||||||
|  |                         ${gettext("Based on the Hashed User ID")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value="${OAuth2ProviderSubModeEnum.UserUsername}" ?selected=${this.provider?.subMode === OAuth2ProviderSubModeEnum.UserUsername}> | ||||||
|  |                         ${gettext("Based on the username")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value="${OAuth2ProviderSubModeEnum.UserEmail}" ?selected=${this.provider?.subMode === OAuth2ProviderSubModeEnum.UserEmail}> | ||||||
|  |                         ${gettext("Based on the User's Email. This is recommended over the UPN method.")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value="${OAuth2ProviderSubModeEnum.UserUpn}" ?selected=${this.provider?.subMode === OAuth2ProviderSubModeEnum.UserUpn}> | ||||||
|  |                         ${gettext("Based on the User's UPN, only works if user has a 'upn' attribute set. Use this method only if you have different UPN and Mail domains.")} | ||||||
|  |                     </option> | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text"> | ||||||
|  |                     ${gettext("Configure what data should be used as unique User Identifier. For most cases, the default should be fine.")} | ||||||
|  |                 </p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal name="includeClaimsInIdToken"> | ||||||
|  |                 <div class="pf-c-check"> | ||||||
|  |                     <input type="checkbox" class="pf-c-check__input" ?checked=${this.provider?.includeClaimsInIdToken || false}> | ||||||
|  |                     <label class="pf-c-check__label"> | ||||||
|  |                         ${gettext("Include claims in id_token")} | ||||||
|  |                     </label> | ||||||
|  |                 </div> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Include User claims from scopes in the id_token, for applications that don't access the userinfo endpoint.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Issuer mode")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="issuerMode"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value="${OAuth2ProviderIssuerModeEnum.PerProvider}" ?selected=${this.provider?.issuerMode === OAuth2ProviderIssuerModeEnum.PerProvider}> | ||||||
|  |                         ${gettext("Each provider has a different issuer, based on the application slug.")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value="${OAuth2ProviderIssuerModeEnum.Global}" ?selected=${this.provider?.issuerMode === OAuth2ProviderIssuerModeEnum.Global}> | ||||||
|  |                         ${gettext("Same identifier is used for all providers")} | ||||||
|  |                     </option> | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text"> | ||||||
|  |                     ${gettext("Configure how the issuer field of the ID Token should be filled.")} | ||||||
|  |                 </p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |         </form>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -9,23 +9,23 @@ import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList | |||||||
| import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css"; | import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css"; | ||||||
| import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css"; | import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css"; | ||||||
| import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css"; | import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css"; | ||||||
| import AKGlobal from "../../authentik.css"; | import AKGlobal from "../../../authentik.css"; | ||||||
| import PFBase from "@patternfly/patternfly/patternfly-base.css"; | import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||||
| import PFForm from "@patternfly/patternfly/components/Form/form.css"; | import PFForm from "@patternfly/patternfly/components/Form/form.css"; | ||||||
| import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; | import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; | ||||||
| 
 | 
 | ||||||
| import "../../elements/buttons/ModalButton"; | import "../../../elements/buttons/ModalButton"; | ||||||
| import "../../elements/buttons/SpinnerButton"; | import "../../../elements/buttons/SpinnerButton"; | ||||||
| import "../../elements/CodeMirror"; | import "../../../elements/CodeMirror"; | ||||||
| import "../../elements/Tabs"; | import "../../../elements/Tabs"; | ||||||
| import "../../elements/events/ObjectChangelog"; | import "../../../elements/events/ObjectChangelog"; | ||||||
| import "./RelatedApplicationButton"; | import "../RelatedApplicationButton"; | ||||||
| import { Page } from "../../elements/Page"; | import "./OAuth2ProviderForm"; | ||||||
| import { convertToTitle } from "../../utils"; | import { Page } from "../../../elements/Page"; | ||||||
|  | import { convertToTitle } from "../../../utils"; | ||||||
| import { OAuth2Provider, OAuth2ProviderSetupURLs, ProvidersApi } from "authentik-api"; | import { OAuth2Provider, OAuth2ProviderSetupURLs, ProvidersApi } from "authentik-api"; | ||||||
| import { DEFAULT_CONFIG } from "../../api/Config"; | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
| import { AdminURLManager } from "../../api/legacy"; | import { EVENT_REFRESH } from "../../../constants"; | ||||||
| import { EVENT_REFRESH } from "../../constants"; |  | ||||||
| 
 | 
 | ||||||
| @customElement("ak-provider-oauth2-view") | @customElement("ak-provider-oauth2-view") | ||||||
| export class OAuth2ProviderViewPage extends Page { | export class OAuth2ProviderViewPage extends Page { | ||||||
| @ -128,12 +128,21 @@ export class OAuth2ProviderViewPage extends Page { | |||||||
|                                     </dl> |                                     </dl> | ||||||
|                                 </div> |                                 </div> | ||||||
|                                 <div class="pf-c-card__footer"> |                                 <div class="pf-c-card__footer"> | ||||||
|                                     <ak-modal-button href="${AdminURLManager.providers(`${this.provider.pk}/update/`)}"> |                                     <ak-forms-modal> | ||||||
|                                         <ak-spinner-button slot="trigger" class="pf-m-primary"> |                                         <span slot="submit"> | ||||||
|  |                                             ${gettext("Update")} | ||||||
|  |                                         </span> | ||||||
|  |                                         <span slot="header"> | ||||||
|  |                                             ${gettext("Update OAuth2 Provider")} | ||||||
|  |                                         </span> | ||||||
|  |                                         <ak-provider-oauth2-form | ||||||
|  |                                             slot="form" | ||||||
|  |                                             .providerUUID=${this.provider.pk || 0}> | ||||||
|  |                                         </ak-provider-oauth2-form> | ||||||
|  |                                         <button slot="trigger" class="pf-c-button pf-m-primary"> | ||||||
|                                             ${gettext("Edit")} |                                             ${gettext("Edit")} | ||||||
|                                         </ak-spinner-button> |                                         </button> | ||||||
|                                         <div slot="modal"></div> |                                     </ak-forms-modal> | ||||||
|                                     </ak-modal-button> |  | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
							
								
								
									
										139
									
								
								web/src/pages/providers/proxy/ProxyProviderForm.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								web/src/pages/providers/proxy/ProxyProviderForm.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,139 @@ | |||||||
|  | import { CryptoApi, FlowDesignationEnum, FlowsApi, ProvidersApi, ProxyProvider } from "authentik-api"; | ||||||
|  | import { gettext } from "django"; | ||||||
|  | import { customElement, property } from "lit-element"; | ||||||
|  | import { html, TemplateResult } from "lit-html"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import { Form } from "../../../elements/forms/Form"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  | import "../../../elements/forms/HorizontalFormElement"; | ||||||
|  |  | ||||||
|  | @customElement("ak-provider-proxy-form") | ||||||
|  | export class ProxyProviderFormPage extends Form<ProxyProvider> { | ||||||
|  |  | ||||||
|  |     set providerUUID(value: number) { | ||||||
|  |         new ProvidersApi(DEFAULT_CONFIG).providersProxyRead({ | ||||||
|  |             id: value, | ||||||
|  |         }).then(provider => { | ||||||
|  |             this.provider = provider; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @property({attribute: false}) | ||||||
|  |     provider?: ProxyProvider; | ||||||
|  |  | ||||||
|  |     getSuccessMessage(): string { | ||||||
|  |         if (this.provider) { | ||||||
|  |             return gettext("Successfully updated provider."); | ||||||
|  |         } else { | ||||||
|  |             return gettext("Successfully created provider."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send = (data: ProxyProvider): Promise<ProxyProvider> => { | ||||||
|  |         if (this.provider) { | ||||||
|  |             return new ProvidersApi(DEFAULT_CONFIG).providersProxyUpdate({ | ||||||
|  |                 id: this.provider.pk || 0, | ||||||
|  |                 data: data | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             return new ProvidersApi(DEFAULT_CONFIG).providersProxyCreate({ | ||||||
|  |                 data: data | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     renderForm(): TemplateResult { | ||||||
|  |         return html`<form class="pf-c-form pf-m-horizontal"> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Name")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="name"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.name)}" class="pf-c-form-control" required> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Authorization flow")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="authorizationFlow"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     ${until(new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({ | ||||||
|  |                         ordering: "pk", | ||||||
|  |                         designation: FlowDesignationEnum.Authorization, | ||||||
|  |                     }).then(flows => { | ||||||
|  |                         return flows.results.map(flow => { | ||||||
|  |                             return html`<option value=${ifDefined(flow.pk)} ?selected=${this.provider?.authorizationFlow === flow.pk}>${flow.name}</option>`; | ||||||
|  |                         }); | ||||||
|  |                     }))} | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Flow used when authorizing this provider.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Internal host")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="internalHost"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.internalHost)}" class="pf-c-form-control" required> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal name="internalHostSslValidation"> | ||||||
|  |                 <div class="pf-c-check"> | ||||||
|  |                     <input type="checkbox" class="pf-c-check__input" ?checked=${this.provider?.internalHostSslValidation || false}> | ||||||
|  |                     <label class="pf-c-check__label"> | ||||||
|  |                         ${gettext("Internal host SSL Validation")} | ||||||
|  |                     </label> | ||||||
|  |                 </div> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Validate SSL Certificates of upstream servers.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("External host")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="externalHost"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.externalHost)}" class="pf-c-form-control" required> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Certificate")} | ||||||
|  |                 name="certificate"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     ${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({ | ||||||
|  |                         ordering: "pk", | ||||||
|  |                         hasKey: "true", | ||||||
|  |                     }).then(keys => { | ||||||
|  |                         return keys.results.map(key => { | ||||||
|  |                             return html`<option value=${ifDefined(key.pk)} ?selected=${this.provider?.certificate === key.pk}>${key.name}</option>`; | ||||||
|  |                         }); | ||||||
|  |                     }))} | ||||||
|  |                 </select> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Skip path regex")} | ||||||
|  |                 name="skipPathRegex"> | ||||||
|  |                 <textarea class="pf-c-form-control">${this.provider?.skipPathRegex}</textarea> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Regular expressions for which authentication is not required. Each new line is interpreted as a new Regular Expression.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal name="basicAuthEnabled"> | ||||||
|  |                 <div class="pf-c-check"> | ||||||
|  |                     <input type="checkbox" class="pf-c-check__input" ?checked=${this.provider?.basicAuthEnabled || false}> | ||||||
|  |                     <label class="pf-c-check__label"> | ||||||
|  |                         ${gettext("Set HTTP-Basic Authentication")} | ||||||
|  |                     </label> | ||||||
|  |                 </div> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Set a custom HTTP-Basic Authentication header based on values from authentik.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("HTTP-Basic Username Key")} | ||||||
|  |                 name="basicAuthUserAttribute"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.basicAuthUserAttribute)}" class="pf-c-form-control"> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("User/Group Attribute used for the user part of the HTTP-Basic Header. If not set, the user's Email address is used.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("HTTP-Basic Password Key")} | ||||||
|  |                 name="basicAuthPasswordAttribute"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.basicAuthPasswordAttribute)}" class="pf-c-form-control"> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("User/Group Attribute used for the password part of the HTTP-Basic Header.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |         </form>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -9,20 +9,20 @@ import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList | |||||||
| import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css"; | import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css"; | ||||||
| import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css"; | import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css"; | ||||||
| import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css"; | import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css"; | ||||||
| import AKGlobal from "../../authentik.css"; |  | ||||||
| import PFBase from "@patternfly/patternfly/patternfly-base.css"; | import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||||
|  | import AKGlobal from "../../../authentik.css"; | ||||||
| 
 | 
 | ||||||
| import "../../elements/buttons/ModalButton"; | import "../../../elements/buttons/ModalButton"; | ||||||
| import "../../elements/buttons/SpinnerButton"; | import "../../../elements/buttons/SpinnerButton"; | ||||||
| import "../../elements/CodeMirror"; | import "../../../elements/CodeMirror"; | ||||||
| import "../../elements/Tabs"; | import "../../../elements/Tabs"; | ||||||
| import "../../elements/events/ObjectChangelog"; | import "../../../elements/events/ObjectChangelog"; | ||||||
| import "./RelatedApplicationButton"; | import "../RelatedApplicationButton"; | ||||||
| import { Page } from "../../elements/Page"; | import "./ProxyProviderForm"; | ||||||
|  | import { Page } from "../../../elements/Page"; | ||||||
| import { ProvidersApi, ProxyProvider } from "authentik-api"; | import { ProvidersApi, ProxyProvider } from "authentik-api"; | ||||||
| import { DEFAULT_CONFIG } from "../../api/Config"; | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
| import { AdminURLManager } from "../../api/legacy"; | import { EVENT_REFRESH } from "../../../constants"; | ||||||
| import { EVENT_REFRESH } from "../../constants"; |  | ||||||
| 
 | 
 | ||||||
| @customElement("ak-provider-proxy-view") | @customElement("ak-provider-proxy-view") | ||||||
| export class ProxyProviderViewPage extends Page { | export class ProxyProviderViewPage extends Page { | ||||||
| @ -128,12 +128,21 @@ export class ProxyProviderViewPage extends Page { | |||||||
|                                     </dl> |                                     </dl> | ||||||
|                                 </div> |                                 </div> | ||||||
|                                 <div class="pf-c-card__footer"> |                                 <div class="pf-c-card__footer"> | ||||||
|                                     <ak-modal-button href="${AdminURLManager.providers(`${this.provider.pk}/update/`)}"> |                                     <ak-forms-modal> | ||||||
|                                         <ak-spinner-button slot="trigger" class="pf-m-primary"> |                                         <span slot="submit"> | ||||||
|  |                                             ${gettext("Update")} | ||||||
|  |                                         </span> | ||||||
|  |                                         <span slot="header"> | ||||||
|  |                                             ${gettext("Update Proxy Provider")} | ||||||
|  |                                         </span> | ||||||
|  |                                         <ak-provider-proxy-form | ||||||
|  |                                             slot="form" | ||||||
|  |                                             .providerUUID=${this.provider.pk || 0}> | ||||||
|  |                                         </ak-provider-proxy-form> | ||||||
|  |                                         <button slot="trigger" class="pf-c-button pf-m-primary"> | ||||||
|                                             ${gettext("Edit")} |                                             ${gettext("Edit")} | ||||||
|                                         </ak-spinner-button> |                                         </button> | ||||||
|                                         <div slot="modal"></div> |                                     </ak-forms-modal> | ||||||
|                                     </ak-modal-button> |  | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
							
								
								
									
										237
									
								
								web/src/pages/providers/saml/SAMLProviderForm.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								web/src/pages/providers/saml/SAMLProviderForm.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,237 @@ | |||||||
|  | import { CryptoApi, FlowDesignationEnum, FlowsApi, SAMLProvider, ProvidersApi, PropertymappingsApi,  SAMLProviderSpBindingEnum, SAMLProviderDigestAlgorithmEnum, SAMLProviderSignatureAlgorithmEnum } from "authentik-api"; | ||||||
|  | import { gettext } from "django"; | ||||||
|  | import { customElement, property } from "lit-element"; | ||||||
|  | import { html, TemplateResult } from "lit-html"; | ||||||
|  | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
|  | import { Form } from "../../../elements/forms/Form"; | ||||||
|  | import { until } from "lit-html/directives/until"; | ||||||
|  | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
|  | import "../../../elements/forms/HorizontalFormElement"; | ||||||
|  |  | ||||||
|  | @customElement("ak-provider-saml-form") | ||||||
|  | export class SAMLProviderFormPage extends Form<SAMLProvider> { | ||||||
|  |  | ||||||
|  |     set providerUUID(value: number) { | ||||||
|  |         new ProvidersApi(DEFAULT_CONFIG).providersSamlRead({ | ||||||
|  |             id: value, | ||||||
|  |         }).then(provider => { | ||||||
|  |             this.provider = provider; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @property({attribute: false}) | ||||||
|  |     provider?: SAMLProvider; | ||||||
|  |  | ||||||
|  |     getSuccessMessage(): string { | ||||||
|  |         if (this.provider) { | ||||||
|  |             return gettext("Successfully updated provider."); | ||||||
|  |         } else { | ||||||
|  |             return gettext("Successfully created provider."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     send = (data: SAMLProvider): Promise<SAMLProvider> => { | ||||||
|  |         if (this.provider) { | ||||||
|  |             return new ProvidersApi(DEFAULT_CONFIG).providersSamlUpdate({ | ||||||
|  |                 id: this.provider.pk || 0, | ||||||
|  |                 data: data | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             return new ProvidersApi(DEFAULT_CONFIG).providersSamlCreate({ | ||||||
|  |                 data: data | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     renderForm(): TemplateResult { | ||||||
|  |         return html`<form class="pf-c-form pf-m-horizontal"> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Name")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="name"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.name)}" class="pf-c-form-control" required> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Authorization flow")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="authorizationFlow"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     ${until(new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({ | ||||||
|  |                         ordering: "pk", | ||||||
|  |                         designation: FlowDesignationEnum.Authorization, | ||||||
|  |                     }).then(flows => { | ||||||
|  |                         return flows.results.map(flow => { | ||||||
|  |                             return html`<option value=${ifDefined(flow.pk)} ?selected=${this.provider?.authorizationFlow === flow.pk}>${flow.name}</option>`; | ||||||
|  |                         }); | ||||||
|  |                     }))} | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Flow used when authorizing this provider.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("ACS URL")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="acsUrl"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.acsUrl)}" class="pf-c-form-control" required> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Issuer")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="issuer"> | ||||||
|  |                 <input type="text" value="${this.provider?.issuer || "authentik"}" class="pf-c-form-control" required> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Service Provider Binding")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="spBinding"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value=${SAMLProviderSpBindingEnum.Redirect} ?selected=${this.provider?.spBinding === SAMLProviderSpBindingEnum.Redirect}> | ||||||
|  |                         ${gettext("Redirect")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${SAMLProviderSpBindingEnum.Post} ?selected=${this.provider?.spBinding === SAMLProviderSpBindingEnum.Post}> | ||||||
|  |                         ${gettext("Post")} | ||||||
|  |                     </option> | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Determines how authentik sends the response back to the Service Provider.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Audience")} | ||||||
|  |                 name="audience"> | ||||||
|  |                 <input type="text" value="${ifDefined(this.provider?.audience)}" class="pf-c-form-control"> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Signing Keypair")} | ||||||
|  |                 name="signingKp"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value="" ?selected=${this.provider?.signingKp === undefined}>---------</option> | ||||||
|  |                     ${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({ | ||||||
|  |                         ordering: "pk", | ||||||
|  |                         hasKey: "true", | ||||||
|  |                     }).then(keys => { | ||||||
|  |                         return keys.results.map(key => { | ||||||
|  |                             return html`<option value=${ifDefined(key.pk)} ?selected=${this.provider?.signingKp === key.pk}>${key.name}</option>`; | ||||||
|  |                         }); | ||||||
|  |                     }))} | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Keypair used to sign outgoing Responses going to the Service Provider.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Verification Certificate")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="verificationKp"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value="" ?selected=${this.provider?.verificationKp === undefined}>---------</option> | ||||||
|  |                     ${until(new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsList({ | ||||||
|  |                         ordering: "pk", | ||||||
|  |                     }).then(keys => { | ||||||
|  |                         return keys.results.map(key => { | ||||||
|  |                             return html`<option value=${ifDefined(key.pk)} ?selected=${this.provider?.verificationKp === key.pk}>${key.name}</option>`; | ||||||
|  |                         }); | ||||||
|  |                     }))} | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Property mappings")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="propertyMappings"> | ||||||
|  |                 <select class="pf-c-form-control" multiple> | ||||||
|  |                     ${until(new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSamlList({ | ||||||
|  |                         ordering: "saml_name" | ||||||
|  |                     }).then(mappings => { | ||||||
|  |                         return mappings.results.map(mapping => { | ||||||
|  |                             const selected = Array.from(this.provider?.propertyMappings || []).some(su => { | ||||||
|  |                                 return su == mapping.pk; | ||||||
|  |                             }); | ||||||
|  |                             return html`<option value=${ifDefined(mapping.pk)} ?selected=${selected}>${mapping.name}</option>`; | ||||||
|  |                         }); | ||||||
|  |                     }))} | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Hold control/command to select multiple items.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("NameID Property Mapping")} | ||||||
|  |                 name="nameIdMapping"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value="" ?selected=${this.provider?.nameIdMapping === undefined}>---------</option> | ||||||
|  |                     ${until(new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSamlList({ | ||||||
|  |                         ordering: "saml_name" | ||||||
|  |                     }).then(mappings => { | ||||||
|  |                         return mappings.results.map(mapping => { | ||||||
|  |                             return html`<option value=${ifDefined(mapping.pk)} ?selected=${this.provider?.nameIdMapping === mapping.pk}>${mapping.name}</option>`; | ||||||
|  |                         }); | ||||||
|  |                     }))} | ||||||
|  |                 </select> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Configure how the NameID value will be created. When left empty, the NameIDPolicy of the incoming request will be respected.")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Assertion valid not before")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="assertionValidNotBefore"> | ||||||
|  |                 <input type="text" value="${this.provider?.assertionValidNotBefore || "minutes=-5"}" class="pf-c-form-control" required> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Assertion valid not before current time + this value (Format: hours=-1;minutes=-2;seconds=-3).")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Assertion valid not on or after")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="assertionValidNotOnOrAfter"> | ||||||
|  |                 <input type="text" value="${this.provider?.assertionValidNotOnOrAfter || "minutes=5"}" class="pf-c-form-control" required> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Assertion not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Session valid not on or after")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="sessionValidNotOnOrAfter"> | ||||||
|  |                 <input type="text" value="${this.provider?.sessionValidNotOnOrAfter || "minutes=86400"}" class="pf-c-form-control" required> | ||||||
|  |                 <p class="pf-c-form__helper-text">${gettext("Session not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).")}</p> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |  | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Digest algorithm")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="digestAlgorithm"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value=${SAMLProviderDigestAlgorithmEnum._200009Xmldsigsha1} ?selected=${this.provider?.digestAlgorithm === SAMLProviderDigestAlgorithmEnum._200009Xmldsigsha1}> | ||||||
|  |                         ${gettext("SHA1")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${SAMLProviderDigestAlgorithmEnum._200104Xmlencsha256} ?selected=${this.provider?.digestAlgorithm === SAMLProviderDigestAlgorithmEnum._200104Xmlencsha256 || this.provider?.digestAlgorithm === undefined}> | ||||||
|  |                         ${gettext("SHA256")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${SAMLProviderDigestAlgorithmEnum._200104XmldsigMoresha384} ?selected=${this.provider?.digestAlgorithm === SAMLProviderDigestAlgorithmEnum._200104XmldsigMoresha384}> | ||||||
|  |                         ${gettext("SHA384")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${SAMLProviderDigestAlgorithmEnum._200104Xmlencsha512} ?selected=${this.provider?.digestAlgorithm === SAMLProviderDigestAlgorithmEnum._200104Xmlencsha512}> | ||||||
|  |                         ${gettext("SHA512")} | ||||||
|  |                     </option> | ||||||
|  |                 </select> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |             <ak-form-element-horizontal | ||||||
|  |                 label=${gettext("Signature algorithm")} | ||||||
|  |                 ?required=${true} | ||||||
|  |                 name="signatureAlgorithm"> | ||||||
|  |                 <select class="pf-c-form-control"> | ||||||
|  |                     <option value=${SAMLProviderSignatureAlgorithmEnum._200009XmldsigrsaSha1} ?selected=${this.provider?.signatureAlgorithm === SAMLProviderSignatureAlgorithmEnum._200009XmldsigrsaSha1}> | ||||||
|  |                         ${gettext("RSA-SHA1")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha256} ?selected=${this.provider?.signatureAlgorithm === SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha256 || this.provider?.signatureAlgorithm === undefined}> | ||||||
|  |                         ${gettext("RSA-SHA256")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha384} ?selected=${this.provider?.signatureAlgorithm === SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha384}> | ||||||
|  |                         ${gettext("RSA-SHA384")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha512} ?selected=${this.provider?.signatureAlgorithm === SAMLProviderSignatureAlgorithmEnum._200104XmldsigMorersaSha512}> | ||||||
|  |                         ${gettext("RSA-SHA512")} | ||||||
|  |                     </option> | ||||||
|  |                     <option value=${SAMLProviderSignatureAlgorithmEnum._200009XmldsigdsaSha1} ?selected=${this.provider?.signatureAlgorithm === SAMLProviderSignatureAlgorithmEnum._200009XmldsigdsaSha1}> | ||||||
|  |                         ${gettext("DSA-SHA1")} | ||||||
|  |                     </option> | ||||||
|  |                 </select> | ||||||
|  |             </ak-form-element-horizontal> | ||||||
|  |         </form>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -10,20 +10,21 @@ import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList | |||||||
| import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css"; | import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css"; | ||||||
| import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css"; | import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css"; | ||||||
| import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css"; | import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css"; | ||||||
| import AKGlobal from "../../authentik.css"; | import AKGlobal from "../../../authentik.css"; | ||||||
| import PFBase from "@patternfly/patternfly/patternfly-base.css"; | import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||||
| 
 | 
 | ||||||
| import "../../elements/buttons/ModalButton"; | import "../../../elements/buttons/ModalButton"; | ||||||
| import "../../elements/buttons/SpinnerButton"; | import "../../../elements/buttons/SpinnerButton"; | ||||||
| import "../../elements/CodeMirror"; | import "../../../elements/CodeMirror"; | ||||||
| import "../../elements/Tabs"; | import "../../../elements/Tabs"; | ||||||
| import "../../elements/events/ObjectChangelog"; | import "../../../elements/events/ObjectChangelog"; | ||||||
| import "./RelatedApplicationButton"; | import "../RelatedApplicationButton"; | ||||||
| import { Page } from "../../elements/Page"; | import "./SAMLProviderForm"; | ||||||
|  | import { Page } from "../../../elements/Page"; | ||||||
| import { ProvidersApi, SAMLProvider } from "authentik-api"; | import { ProvidersApi, SAMLProvider } from "authentik-api"; | ||||||
| import { DEFAULT_CONFIG } from "../../api/Config"; | import { DEFAULT_CONFIG } from "../../../api/Config"; | ||||||
| import { AdminURLManager, AppURLManager } from "../../api/legacy"; | import { AppURLManager } from "../../../api/legacy"; | ||||||
| import { EVENT_REFRESH } from "../../constants"; | import { EVENT_REFRESH } from "../../../constants"; | ||||||
| import { ifDefined } from "lit-html/directives/if-defined"; | import { ifDefined } from "lit-html/directives/if-defined"; | ||||||
| 
 | 
 | ||||||
| @customElement("ak-provider-saml-view") | @customElement("ak-provider-saml-view") | ||||||
| @ -121,12 +122,21 @@ export class SAMLProviderViewPage extends Page { | |||||||
|                                     </dl> |                                     </dl> | ||||||
|                                 </div> |                                 </div> | ||||||
|                                 <div class="pf-c-card__footer"> |                                 <div class="pf-c-card__footer"> | ||||||
|                                     <ak-modal-button href="${AdminURLManager.providers(`${this.provider.pk}/update/`)}"> |                                     <ak-forms-modal> | ||||||
|                                         <ak-spinner-button slot="trigger" class="pf-m-primary"> |                                         <span slot="submit"> | ||||||
|  |                                             ${gettext("Update")} | ||||||
|  |                                         </span> | ||||||
|  |                                         <span slot="header"> | ||||||
|  |                                             ${gettext("Update SAML Provider")} | ||||||
|  |                                         </span> | ||||||
|  |                                         <ak-provider-saml-form | ||||||
|  |                                             slot="form" | ||||||
|  |                                             .providerUUID=${this.provider.pk || 0}> | ||||||
|  |                                         </ak-provider-saml-form> | ||||||
|  |                                         <button slot="trigger" class="pf-c-button pf-m-primary"> | ||||||
|                                             ${gettext("Edit")} |                                             ${gettext("Edit")} | ||||||
|                                         </ak-spinner-button> |                                         </button> | ||||||
|                                         <div slot="modal"></div> |                                     </ak-forms-modal> | ||||||
|                                     </ak-modal-button> |  | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer