mirror of https://github.com/status-im/consul.git
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:
commit
2354c06a93
|
@ -53,6 +53,7 @@
|
||||||
<authForm.Method @matches="sso">
|
<authForm.Method @matches="sso">
|
||||||
<OidcSelect
|
<OidcSelect
|
||||||
@dc={{@dc.Name}}
|
@dc={{@dc.Name}}
|
||||||
|
@partition={{@partition}}
|
||||||
@nspace={{@nspace}}
|
@nspace={{@nspace}}
|
||||||
@disabled={{authForm.disabled}}
|
@disabled={{authForm.disabled}}
|
||||||
@onchange={{authForm.submit}}
|
@onchange={{authForm.submit}}
|
||||||
|
|
|
@ -1,76 +1,54 @@
|
||||||
<StateChart
|
<StateChart @src={{this.chart}} as |State Guard ChartAction dispatch state|>
|
||||||
@src={{this.chart}}
|
{{#let
|
||||||
as |State Guard ChartAction dispatch state|>
|
(hash State=State Guard=Guard Action=ChartAction dispatch=dispatch state=state)
|
||||||
{{#let
|
as |chart|
|
||||||
|
}}
|
||||||
|
{{#let
|
||||||
(hash
|
(hash
|
||||||
State=State
|
reset=(action dispatch 'RESET')
|
||||||
Guard=Guard
|
|
||||||
Action=ChartAction
|
|
||||||
dispatch=dispatch
|
|
||||||
state=state
|
|
||||||
)
|
|
||||||
as |chart|}}
|
|
||||||
{{#let
|
|
||||||
(hash
|
|
||||||
reset=(action dispatch "RESET")
|
|
||||||
focus=this.focus
|
focus=this.focus
|
||||||
disabled=(state-matches state "loading")
|
disabled=(state-matches state 'loading')
|
||||||
error=(queue
|
error=(queue
|
||||||
(action dispatch "ERROR")
|
(action dispatch 'ERROR') (action (mut this.error) value='error.errors.firstObject')
|
||||||
(action (mut this.error) value="error.errors.firstObject")
|
|
||||||
)
|
)
|
||||||
submit=(queue
|
submit=(queue (action (mut this.value)) (action dispatch 'SUBMIT'))
|
||||||
(action (mut this.value))
|
|
||||||
(action dispatch "SUBMIT")
|
|
||||||
)
|
)
|
||||||
)
|
as |exported|
|
||||||
as |exported|}}
|
}}
|
||||||
<Guard
|
<Guard @name='hasValue' @cond={{this.hasValue}} />
|
||||||
@name="hasValue"
|
|
||||||
@cond={{this.hasValue}}
|
|
||||||
/>
|
|
||||||
{{!TODO: Call this reset or similar }}
|
{{!TODO: Call this reset or similar }}
|
||||||
<chart.Action
|
<chart.Action
|
||||||
@name="clearError"
|
@name='clearError'
|
||||||
@exec={{queue (action (mut this.error) undefined) (action (mut this.secret) undefined)}}
|
@exec={{queue (action (mut this.error) undefined) (action (mut this.secret) undefined)}}
|
||||||
/>
|
/>
|
||||||
<div
|
<div class='auth-form' ...attributes>
|
||||||
class="auth-form"
|
<StateChart
|
||||||
...attributes
|
|
||||||
>
|
|
||||||
<StateChart
|
|
||||||
@src={{this.tabsChart}}
|
@src={{this.tabsChart}}
|
||||||
as |TabState IgnoredGuard IgnoredAction tabDispatch tabState|>
|
as |TabState IgnoredGuard IgnoredAction tabDispatch tabState|
|
||||||
{{#if (can 'use SSO')}}
|
>
|
||||||
|
{{#if (can 'use SSO')}}
|
||||||
<TabNav
|
<TabNav
|
||||||
@items={{array
|
@items={{array
|
||||||
(hash
|
(hash label='Token' selected=(state-matches tabState 'token'))
|
||||||
label='Token'
|
(hash label='SSO' selected=(state-matches tabState 'sso'))
|
||||||
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}}
|
{{/if}}
|
||||||
<State @matches="error">
|
<State @matches='error'>
|
||||||
{{#if this.error.status}}
|
{{#if this.error.status}}
|
||||||
<Notice
|
<Notice @type='error' role='alert' as |notice|>
|
||||||
@type="error"
|
|
||||||
role="alert"
|
|
||||||
as |notice|>
|
|
||||||
<notice.Body>
|
<notice.Body>
|
||||||
<p>
|
<p>
|
||||||
{{#if this.value.Name}}
|
{{#if this.value.Name}}
|
||||||
{{#if (eq this.error.status '403')}}
|
{{#if (eq this.error.status '403')}}
|
||||||
<strong>Consul login failed</strong><br />
|
<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')}}
|
{{else if (eq this.error.status '401')}}
|
||||||
<strong>Could not log in to provider</strong><br />
|
<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')}}
|
{{else if (eq this.error.status '499')}}
|
||||||
<strong>SSO log in window closed</strong><br />
|
<strong>SSO log in window closed</strong><br />
|
||||||
The OIDC provider window was closed. Please try again.
|
The OIDC provider window was closed. Please try again.
|
||||||
|
@ -95,13 +73,14 @@ as |TabState IgnoredGuard IgnoredAction tabDispatch tabState|>
|
||||||
</Notice>
|
</Notice>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</State>
|
</State>
|
||||||
<TabState @matches="token">
|
<TabState @matches='token'>
|
||||||
<form
|
<form onsubmit={{action dispatch 'SUBMIT'}}>
|
||||||
onsubmit={{action dispatch "SUBMIT"}}
|
|
||||||
>
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label
|
<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>
|
<span>Log in with a token</span>
|
||||||
|
|
||||||
|
@ -110,55 +89,54 @@ as |TabState IgnoredGuard IgnoredAction tabDispatch tabState|>
|
||||||
{{! turn them into text inputs during acceptance testing }}
|
{{! turn them into text inputs during acceptance testing }}
|
||||||
<input
|
<input
|
||||||
{{did-insert (set this 'input')}}
|
{{did-insert (set this 'input')}}
|
||||||
disabled={{state-matches state "loading"}}
|
disabled={{state-matches state 'loading'}}
|
||||||
type={{if (eq (env 'environment') 'testing') 'text' 'password'}}
|
type={{if (eq (env 'environment') 'testing') 'text' 'password'}}
|
||||||
name="auth[SecretID]"
|
name='auth[SecretID]'
|
||||||
placeholder="SecretID"
|
placeholder='SecretID'
|
||||||
value={{this.secret}}
|
value={{this.secret}}
|
||||||
oninput={{queue
|
oninput={{queue
|
||||||
(action (mut this.secret) value="target.value")
|
(action (mut this.secret) value='target.value')
|
||||||
(action (mut this.value) value="target.value")
|
(action (mut this.value) value='target.value')
|
||||||
(action dispatch "TYPING")
|
(action dispatch 'TYPING')
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<State @matches="error">
|
<State @matches='error'>
|
||||||
{{#if (not this.error.status)}}
|
{{#if (not this.error.status)}}
|
||||||
<strong role="alert">
|
<strong role='alert'>
|
||||||
Please enter your secret
|
Please enter your secret
|
||||||
</strong>
|
</strong>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</State>
|
</State>
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<Action
|
<Action @type='submit' disabled={{state-matches state 'loading'}}>
|
||||||
@type="submit"
|
|
||||||
disabled={{state-matches state "loading"}}
|
|
||||||
>
|
|
||||||
Log in
|
Log in
|
||||||
</Action>
|
</Action>
|
||||||
</form>
|
</form>
|
||||||
</TabState>
|
</TabState>
|
||||||
|
|
||||||
{{yield (assign exported (hash Method=TabState))}}
|
{{yield (assign exported (hash Method=TabState))}}
|
||||||
|
|
||||||
<em>
|
<em>
|
||||||
Contact your administrator for login credentials.
|
Contact your administrator for login credentials.
|
||||||
</em>
|
</em>
|
||||||
</StateChart>
|
</StateChart>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<State @matches="loading">
|
<State @matches='loading'>
|
||||||
<TokenSource
|
<TokenSource
|
||||||
@dc={{@dc}}
|
@dc={{@dc}}
|
||||||
@nspace={{or this.value.Namespace @nspace}}
|
@nspace={{or this.value.Namespace @nspace}}
|
||||||
@partition={{or this.value.Partition @partition}}
|
@partition={{or this.value.Partition @partition}}
|
||||||
@type={{if this.value.Name 'oidc' 'secret'}}
|
@type={{if this.value.Name 'oidc' 'secret'}}
|
||||||
@value={{this.value}}
|
@value={{this.value}}
|
||||||
@onchange={{queue (action dispatch "RESET") @onsubmit}}
|
@onchange={{queue (action dispatch 'RESET') @onsubmit}}
|
||||||
@onerror={{queue (action (mut this.error) value="error.errors.firstObject") (action dispatch "ERROR")}}
|
@onerror={{queue
|
||||||
|
(action (mut this.error) value='error.errors.firstObject')
|
||||||
|
(action dispatch 'ERROR')
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</State>
|
</State>
|
||||||
{{/let}}
|
{{/let}}
|
||||||
{{/let}}
|
{{/let}}
|
||||||
</StateChart>
|
</StateChart>
|
|
@ -1,38 +1,25 @@
|
||||||
<StateChart
|
<StateChart @src={{chart}} as |State Guard ChartAction dispatch state|>
|
||||||
@src={{chart}}
|
{{#let
|
||||||
as |State Guard ChartAction dispatch state|>
|
(hash State=State Guard=Guard Action=ChartAction dispatch=dispatch state=state)
|
||||||
{{#let
|
as |chart|
|
||||||
(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
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
@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>
|
||||||
|
|
||||||
<State @matches="loaded">
|
<State @matches='loaded'>
|
||||||
<Action
|
<Action
|
||||||
{{on 'click' (queue (set this 'partition' '') (fn dispatch "RESET"))}}
|
{{on 'click' (queue (set this 'partition' '') (fn dispatch 'RESET'))}}
|
||||||
class="reset"
|
class='reset'
|
||||||
>
|
>
|
||||||
Choose different Partition
|
Choose different Partition
|
||||||
</Action>
|
</Action>
|
||||||
|
@ -40,10 +27,11 @@ as |chart|}}
|
||||||
|
|
||||||
<StateChart
|
<StateChart
|
||||||
@src={{state-chart 'validate'}}
|
@src={{state-chart 'validate'}}
|
||||||
as |ignoredState ignoredGuard ignoredAction formDispatch state|>
|
as |ignoredState ignoredGuard ignoredAction formDispatch state|
|
||||||
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
@name="partition"
|
@name='partition'
|
||||||
@label="Admin Partition"
|
@label='Admin Partition'
|
||||||
@item={{this}}
|
@item={{this}}
|
||||||
@validations={{hash
|
@validations={{hash
|
||||||
partition=(array
|
partition=(array
|
||||||
|
@ -53,20 +41,17 @@ as |chart|}}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
@placeholder="Enter your Partition"
|
@placeholder='Enter your Partition'
|
||||||
@oninput={{action (mut this.partition) value="target.value"}}
|
@oninput={{action (mut this.partition) value='target.value'}}
|
||||||
@chart={{hash
|
@chart={{hash state=state dispatch=formDispatch}}
|
||||||
state=state
|
|
||||||
dispatch=formDispatch
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{{! this belongs to the outer StateChart but we need }}
|
{{! this belongs to the outer StateChart but we need }}
|
||||||
{{! to understand validation state }}
|
{{! to understand validation state }}
|
||||||
<State @matches="idle">
|
<State @matches='idle'>
|
||||||
<Action
|
<Action
|
||||||
{{disabled (or (lt this.partition.length 1) (state-matches state "error"))}}
|
{{disabled (or (lt this.partition.length 1) (state-matches state 'error'))}}
|
||||||
{{on "click" (fn dispatch "LOAD")}}
|
{{on 'click' (fn dispatch 'LOAD')}}
|
||||||
>
|
>
|
||||||
Choose provider
|
Choose provider
|
||||||
</Action>
|
</Action>
|
||||||
|
@ -74,11 +59,11 @@ as |chart|}}
|
||||||
|
|
||||||
</StateChart>
|
</StateChart>
|
||||||
|
|
||||||
<State @matches="loading">
|
<State @matches='loading'>
|
||||||
<Progress aria-label="Loading" />
|
<Progress aria-label='Loading' />
|
||||||
</State>
|
</State>
|
||||||
|
|
||||||
<State @matches="loaded">
|
<State @matches='loaded'>
|
||||||
{{#if (lt this.items.length 3)}}
|
{{#if (lt this.items.length 3)}}
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -87,10 +72,12 @@ as |chart|}}
|
||||||
<Action
|
<Action
|
||||||
class={{concat item.Kind '-oidc-provider'}}
|
class={{concat item.Kind '-oidc-provider'}}
|
||||||
disabled={{@disabled}}
|
disabled={{@disabled}}
|
||||||
@type="button"
|
@type='button'
|
||||||
{{on 'click' (fn @onchange item)}}
|
{{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>
|
</Action>
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
@ -101,8 +88,8 @@ as |chart|}}
|
||||||
{{#let (or this.provider (object-at 0 this.items)) as |item|}}
|
{{#let (or this.provider (object-at 0 this.items)) as |item|}}
|
||||||
|
|
||||||
<OptionInput
|
<OptionInput
|
||||||
@label="SSO Provider"
|
@label='SSO Provider'
|
||||||
@name="provider"
|
@name='provider'
|
||||||
@item={{this}}
|
@item={{this}}
|
||||||
@selected={{item}}
|
@selected={{item}}
|
||||||
@items={{this.items}}
|
@items={{this.items}}
|
||||||
|
@ -110,19 +97,15 @@ as |chart|}}
|
||||||
@disabled={{@disabled}}
|
@disabled={{@disabled}}
|
||||||
>
|
>
|
||||||
<:option as |option|>
|
<:option as |option|>
|
||||||
<span
|
<span class={{concat option.item.Kind '-oidc-provider'}}>
|
||||||
class={{concat option.item.Kind '-oidc-provider'}}
|
{{or option.item.DisplayName option.item.Name}}{{#if
|
||||||
>
|
(not-eq option.item.Namespace 'default')
|
||||||
{{or option.item.DisplayName option.item.Name}}{{#if (not-eq option.item.Namespace 'default')}} ({{option.item.Namespace}}){{/if}}
|
}} ({{option.item.Namespace}}){{/if}}
|
||||||
</span>
|
</span>
|
||||||
</:option>
|
</:option>
|
||||||
</OptionInput>
|
</OptionInput>
|
||||||
|
|
||||||
<Action
|
<Action @type='button' {{disabled @disabled}} {{on 'click' (fn @onchange item)}}>
|
||||||
@type="button"
|
|
||||||
{{disabled @disabled}}
|
|
||||||
{{on 'click' (fn @onchange item)}}
|
|
||||||
>
|
|
||||||
Log in
|
Log in
|
||||||
</Action>
|
</Action>
|
||||||
|
|
||||||
|
@ -130,5 +113,5 @@ as |chart|}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</State>
|
</State>
|
||||||
</div>
|
</div>
|
||||||
{{/let}}
|
{{/let}}
|
||||||
</StateChart>
|
</StateChart>
|
|
@ -4,9 +4,14 @@ import { tracked } from '@glimmer/tracking';
|
||||||
import chart from './chart.xstate';
|
import chart from './chart.xstate';
|
||||||
|
|
||||||
export default class OidcSelect extends Component {
|
export default class OidcSelect extends Component {
|
||||||
@tracked partition = '';
|
@tracked partition = 'default';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
this.chart = chart;
|
this.chart = chart;
|
||||||
|
|
||||||
|
if (this.args.partition) {
|
||||||
|
this.partition = this.args.partition;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ Feature: login
|
||||||
---
|
---
|
||||||
And I click login on the navigation
|
And I click login on the navigation
|
||||||
And I click "[data-test-tab=tab_sso] button"
|
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 type "partition" into "[name=partition]"
|
||||||
And I click ".oidc-select button"
|
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"
|
Then a GET request was made to "/v1/internal/ui/oidc-auth-methods?dc=dc-1&ns=@namespace&partition=partition"
|
||||||
|
|
|
@ -85,5 +85,13 @@ export default function (scenario, assert, pauseUntil, find, currentURL, clipboa
|
||||||
})
|
})
|
||||||
.then(['the title should be "$title"'], function (title) {
|
.then(['the title should be "$title"'], function (title) {
|
||||||
assert.equal(document.title, title, `Expected the document.title to equal "${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}`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue