Merge pull request #15085 from hashicorp/ui/feature/net-889-prepopulate-partition-sso-login

ui: NET-889 pre-populate partition SSO login
This commit is contained in:
Tyler Wendlandt 2022-10-21 09:07:04 -06:00 committed by GitHub
commit 2354c06a93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 261 additions and 285 deletions

View File

@ -53,6 +53,7 @@
<authForm.Method @matches="sso">
<OidcSelect
@dc={{@dc.Name}}
@partition={{@partition}}
@nspace={{@nspace}}
@disabled={{authForm.disabled}}
@onchange={{authForm.submit}}

View File

@ -1,76 +1,54 @@
<StateChart
@src={{this.chart}}
as |State Guard ChartAction dispatch state|>
<StateChart @src={{this.chart}} as |State Guard ChartAction dispatch state|>
{{#let
(hash State=State Guard=Guard Action=ChartAction dispatch=dispatch state=state)
as |chart|
}}
{{#let
(hash
State=State
Guard=Guard
Action=ChartAction
dispatch=dispatch
state=state
)
as |chart|}}
{{#let
(hash
reset=(action dispatch "RESET")
reset=(action dispatch 'RESET')
focus=this.focus
disabled=(state-matches state "loading")
disabled=(state-matches state 'loading')
error=(queue
(action dispatch "ERROR")
(action (mut this.error) value="error.errors.firstObject")
(action dispatch 'ERROR') (action (mut this.error) value='error.errors.firstObject')
)
submit=(queue
(action (mut this.value))
(action dispatch "SUBMIT")
submit=(queue (action (mut this.value)) (action dispatch 'SUBMIT'))
)
)
as |exported|}}
<Guard
@name="hasValue"
@cond={{this.hasValue}}
/>
as |exported|
}}
<Guard @name='hasValue' @cond={{this.hasValue}} />
{{!TODO: Call this reset or similar }}
<chart.Action
@name="clearError"
@name='clearError'
@exec={{queue (action (mut this.error) undefined) (action (mut this.secret) undefined)}}
/>
<div
class="auth-form"
...attributes
>
<div class='auth-form' ...attributes>
<StateChart
@src={{this.tabsChart}}
as |TabState IgnoredGuard IgnoredAction tabDispatch tabState|>
as |TabState IgnoredGuard IgnoredAction tabDispatch tabState|
>
{{#if (can 'use SSO')}}
<TabNav
@items={{array
(hash
label='Token'
selected=(state-matches tabState 'token')
)
(hash
label='SSO'
selected=(state-matches tabState 'sso')
)
(hash label='Token' selected=(state-matches tabState 'token'))
(hash label='SSO' selected=(state-matches tabState 'sso'))
}}
@onclick={{queue (action tabDispatch) (action dispatch "RESET")}}
@onclick={{queue (action tabDispatch) (action dispatch 'RESET')}}
/>
{{/if}}
<State @matches="error">
<State @matches='error'>
{{#if this.error.status}}
<Notice
@type="error"
role="alert"
as |notice|>
<Notice @type='error' role='alert' as |notice|>
<notice.Body>
<p>
{{#if this.value.Name}}
{{#if (eq this.error.status '403')}}
<strong>Consul login failed</strong><br />
We received a token from your OIDC provider but could not log in to Consul with it.
We received a token from your OIDC provider but could not log in to Consul
with it.
{{else if (eq this.error.status '401')}}
<strong>Could not log in to provider</strong><br />
The OIDC provider has rejected this access token. Please have an administrator check your auth method configuration.
The OIDC provider has rejected this access token. Please have an
administrator check your auth method configuration.
{{else if (eq this.error.status '499')}}
<strong>SSO log in window closed</strong><br />
The OIDC provider window was closed. Please try again.
@ -95,13 +73,14 @@ as |TabState IgnoredGuard IgnoredAction tabDispatch tabState|>
</Notice>
{{/if}}
</State>
<TabState @matches="token">
<form
onsubmit={{action dispatch "SUBMIT"}}
>
<TabState @matches='token'>
<form onsubmit={{action dispatch 'SUBMIT'}}>
<fieldset>
<label
class={{concat "type-password" (if (and (state-matches state 'error') (not this.error.status)) ' has-error')}}
class={{concat
'type-password'
(if (and (state-matches state 'error') (not this.error.status)) ' has-error')
}}
>
<span>Log in with a token</span>
@ -110,30 +89,27 @@ as |TabState IgnoredGuard IgnoredAction tabDispatch tabState|>
{{! turn them into text inputs during acceptance testing }}
<input
{{did-insert (set this 'input')}}
disabled={{state-matches state "loading"}}
disabled={{state-matches state 'loading'}}
type={{if (eq (env 'environment') 'testing') 'text' 'password'}}
name="auth[SecretID]"
placeholder="SecretID"
name='auth[SecretID]'
placeholder='SecretID'
value={{this.secret}}
oninput={{queue
(action (mut this.secret) value="target.value")
(action (mut this.value) value="target.value")
(action dispatch "TYPING")
(action (mut this.secret) value='target.value')
(action (mut this.value) value='target.value')
(action dispatch 'TYPING')
}}
/>
<State @matches="error">
<State @matches='error'>
{{#if (not this.error.status)}}
<strong role="alert">
<strong role='alert'>
Please enter your secret
</strong>
{{/if}}
</State>
</label>
</fieldset>
<Action
@type="submit"
disabled={{state-matches state "loading"}}
>
<Action @type='submit' disabled={{state-matches state 'loading'}}>
Log in
</Action>
</form>
@ -146,17 +122,19 @@ as |TabState IgnoredGuard IgnoredAction tabDispatch tabState|>
</em>
</StateChart>
</div>
<State @matches="loading">
<State @matches='loading'>
<TokenSource
@dc={{@dc}}
@nspace={{or this.value.Namespace @nspace}}
@partition={{or this.value.Partition @partition}}
@type={{if this.value.Name 'oidc' 'secret'}}
@value={{this.value}}
@onchange={{queue (action dispatch "RESET") @onsubmit}}
@onerror={{queue (action (mut this.error) value="error.errors.firstObject") (action dispatch "ERROR")}}
@onchange={{queue (action dispatch 'RESET') @onsubmit}}
@onerror={{queue
(action (mut this.error) value='error.errors.firstObject')
(action dispatch 'ERROR')
}}
/>
</State>
{{/let}}

View File

@ -1,38 +1,25 @@
<StateChart
@src={{chart}}
as |State Guard ChartAction dispatch state|>
<StateChart @src={{chart}} as |State Guard ChartAction dispatch state|>
{{#let
(hash
State=State
Guard=Guard
Action=ChartAction
dispatch=dispatch
state=state
)
as |chart|}}
<div
class="oidc-select"
...attributes
>
<State @notMatches="idle">
<DataSource
@src={{uri '/${partition}/${nspace}/${dc}/oidc/providers'
(hash
partition=this.partition
nspace=@nspace
dc=@dc
)
(hash State=State Guard=Guard Action=ChartAction dispatch=dispatch state=state)
as |chart|
}}
@onchange={{queue (action (mut this.items) value="data") (fn dispatch "SUCCESS")}}
@onerror={{queue (fn dispatch "RESET") @onerror}}
<div class='oidc-select' ...attributes>
<State @notMatches='idle'>
<DataSource
@src={{uri
'/${partition}/${nspace}/${dc}/oidc/providers'
(hash partition=this.partition nspace=@nspace dc=@dc)
}}
@onchange={{queue (action (mut this.items) value='data') (fn dispatch 'SUCCESS')}}
@onerror={{queue (fn dispatch 'RESET') @onerror}}
/>
</State>
<State @matches="loaded">
<State @matches='loaded'>
<Action
{{on 'click' (queue (set this 'partition' '') (fn dispatch "RESET"))}}
class="reset"
{{on 'click' (queue (set this 'partition' '') (fn dispatch 'RESET'))}}
class='reset'
>
Choose different Partition
</Action>
@ -40,10 +27,11 @@ as |chart|}}
<StateChart
@src={{state-chart 'validate'}}
as |ignoredState ignoredGuard ignoredAction formDispatch state|>
as |ignoredState ignoredGuard ignoredAction formDispatch state|
>
<TextInput
@name="partition"
@label="Admin Partition"
@name='partition'
@label='Admin Partition'
@item={{this}}
@validations={{hash
partition=(array
@ -53,20 +41,17 @@ as |chart|}}
)
)
}}
@placeholder="Enter your Partition"
@oninput={{action (mut this.partition) value="target.value"}}
@chart={{hash
state=state
dispatch=formDispatch
}}
@placeholder='Enter your Partition'
@oninput={{action (mut this.partition) value='target.value'}}
@chart={{hash state=state dispatch=formDispatch}}
/>
{{! this belongs to the outer StateChart but we need }}
{{! to understand validation state }}
<State @matches="idle">
<State @matches='idle'>
<Action
{{disabled (or (lt this.partition.length 1) (state-matches state "error"))}}
{{on "click" (fn dispatch "LOAD")}}
{{disabled (or (lt this.partition.length 1) (state-matches state 'error'))}}
{{on 'click' (fn dispatch 'LOAD')}}
>
Choose provider
</Action>
@ -74,11 +59,11 @@ as |chart|}}
</StateChart>
<State @matches="loading">
<Progress aria-label="Loading" />
<State @matches='loading'>
<Progress aria-label='Loading' />
</State>
<State @matches="loaded">
<State @matches='loaded'>
{{#if (lt this.items.length 3)}}
<ul>
@ -87,10 +72,12 @@ as |chart|}}
<Action
class={{concat item.Kind '-oidc-provider'}}
disabled={{@disabled}}
@type="button"
@type='button'
{{on 'click' (fn @onchange item)}}
>
Continue with {{or item.DisplayName item.Name}}{{#if (not-eq item.Namespace 'default')}} ({{item.Namespace}}){{/if}}
Continue with
{{or item.DisplayName item.Name}}{{#if (not-eq item.Namespace 'default')}}
({{item.Namespace}}){{/if}}
</Action>
</li>
{{/each}}
@ -101,8 +88,8 @@ as |chart|}}
{{#let (or this.provider (object-at 0 this.items)) as |item|}}
<OptionInput
@label="SSO Provider"
@name="provider"
@label='SSO Provider'
@name='provider'
@item={{this}}
@selected={{item}}
@items={{this.items}}
@ -110,19 +97,15 @@ as |chart|}}
@disabled={{@disabled}}
>
<:option as |option|>
<span
class={{concat option.item.Kind '-oidc-provider'}}
>
{{or option.item.DisplayName option.item.Name}}{{#if (not-eq option.item.Namespace 'default')}} ({{option.item.Namespace}}){{/if}}
<span class={{concat option.item.Kind '-oidc-provider'}}>
{{or option.item.DisplayName option.item.Name}}{{#if
(not-eq option.item.Namespace 'default')
}} ({{option.item.Namespace}}){{/if}}
</span>
</:option>
</OptionInput>
<Action
@type="button"
{{disabled @disabled}}
{{on 'click' (fn @onchange item)}}
>
<Action @type='button' {{disabled @disabled}} {{on 'click' (fn @onchange item)}}>
Log in
</Action>

View File

@ -4,9 +4,14 @@ import { tracked } from '@glimmer/tracking';
import chart from './chart.xstate';
export default class OidcSelect extends Component {
@tracked partition = '';
@tracked partition = 'default';
constructor() {
super(...arguments);
this.chart = chart;
if (this.args.partition) {
this.partition = this.args.partition;
}
}
}

View File

@ -41,6 +41,7 @@ Feature: login
---
And I click login on the navigation
And I click "[data-test-tab=tab_sso] button"
Then the "[name='partition']" input should have the value "default"
And I type "partition" into "[name=partition]"
And I click ".oidc-select button"
Then a GET request was made to "/v1/internal/ui/oidc-auth-methods?dc=dc-1&ns=@namespace&partition=partition"

View File

@ -85,5 +85,13 @@ export default function (scenario, assert, pauseUntil, find, currentURL, clipboa
})
.then(['the title should be "$title"'], function (title) {
assert.equal(document.title, title, `Expected the document.title to equal "${title}"`);
})
.then(['the "$selector" input should have the value "$value"'], function (selector, value) {
const $el = find(selector);
assert.equal(
$el.value,
value,
`Expected the input at ${selector} to have value ${value}, but it had ${$el.value}`
);
});
}