mirror of
https://github.com/kemko/nomad.git
synced 2026-01-07 10:55:42 +03:00
[sso] OIDC Updates for the UI (#15804)
* Updated UI to handle OIDC method changes * Remove redundant store unload call
This commit is contained in:
@@ -39,15 +39,19 @@ func TestACLAuthMethodListCommand(t *testing.T) {
|
||||
ui := cli.NewMockUi()
|
||||
cmd := &ACLAuthMethodListCommand{Meta: Meta{Ui: ui, flagAddress: url}}
|
||||
|
||||
// Attempt to list auth methods without a valid management token
|
||||
// List with an invalid token works fine
|
||||
invalidToken := mock.ACLToken()
|
||||
code := cmd.Run([]string{"-address=" + url, "-token=" + invalidToken.SecretID})
|
||||
must.One(t, code)
|
||||
must.Zero(t, code)
|
||||
|
||||
// List with a valid management token
|
||||
code = cmd.Run([]string{"-address=" + url, "-token=" + token.SecretID})
|
||||
must.Zero(t, code)
|
||||
|
||||
// List with no token at all
|
||||
code = cmd.Run([]string{"-address=" + url})
|
||||
must.Zero(t, code)
|
||||
|
||||
// Check the output
|
||||
out := ui.OutputWriter.String()
|
||||
must.StrContains(t, out, method.Name)
|
||||
|
||||
@@ -1866,14 +1866,6 @@ func (a *ACL) ListAuthMethods(
|
||||
}
|
||||
defer metrics.MeasureSince([]string{"nomad", "acl", "list_auth_methods"}, time.Now())
|
||||
|
||||
// Resolve the token and ensure it has some form of permissions.
|
||||
acl, err := a.srv.ResolveToken(args.AuthToken)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if acl == nil {
|
||||
return structs.ErrPermissionDenied
|
||||
}
|
||||
|
||||
// Set up and return the blocking query.
|
||||
return a.srv.blockingRPC(&blockingOptions{
|
||||
queryOpts: &args.QueryOptions,
|
||||
|
||||
@@ -17,7 +17,7 @@ export default class AuthMethodAdapter extends ApplicationAdapter {
|
||||
|
||||
/**
|
||||
* @typedef {Object} ACLOIDCAuthURLParams
|
||||
* @property {string} AuthMethod
|
||||
* @property {string} AuthMethodName
|
||||
* @property {string} RedirectUri
|
||||
* @property {string} ClientNonce
|
||||
* @property {Object[]} Meta // NOTE: unsure if array of objects or kv pairs
|
||||
@@ -27,11 +27,11 @@ export default class AuthMethodAdapter extends ApplicationAdapter {
|
||||
* @param {ACLOIDCAuthURLParams} params
|
||||
* @returns
|
||||
*/
|
||||
getAuthURL({ AuthMethod, RedirectUri, ClientNonce, Meta }) {
|
||||
getAuthURL({ AuthMethodName, RedirectUri, ClientNonce, Meta }) {
|
||||
const url = `/${this.namespace}/oidc/auth-url`;
|
||||
return this.ajax(url, 'POST', {
|
||||
data: {
|
||||
AuthMethod,
|
||||
AuthMethodName,
|
||||
RedirectUri,
|
||||
ClientNonce,
|
||||
Meta,
|
||||
|
||||
@@ -90,13 +90,20 @@ export default class Tokens extends Controller {
|
||||
window.localStorage.setItem('nomadOIDCNonce', nonce);
|
||||
window.localStorage.setItem('nomadOIDCAuthMethod', provider);
|
||||
|
||||
let redirectURL;
|
||||
if (Ember.testing) {
|
||||
redirectURL = this.router.currentURL;
|
||||
} else {
|
||||
redirectURL = new URL(window.location.toString());
|
||||
redirectURL.search = '';
|
||||
redirectURL = redirectURL.href;
|
||||
}
|
||||
|
||||
method
|
||||
.getAuthURL({
|
||||
AuthMethod: provider,
|
||||
AuthMethodName: provider,
|
||||
ClientNonce: nonce,
|
||||
RedirectUri: Ember.testing
|
||||
? this.router.currentURL
|
||||
: window.location.toString(),
|
||||
RedirectUri: redirectURL,
|
||||
})
|
||||
.then(({ AuthURL }) => {
|
||||
if (Ember.testing) {
|
||||
@@ -111,7 +118,7 @@ export default class Tokens extends Controller {
|
||||
@tracked state = null;
|
||||
|
||||
get isValidatingToken() {
|
||||
if (this.code && this.state === 'success') {
|
||||
if (this.code && this.state) {
|
||||
this.validateSSO();
|
||||
return true;
|
||||
} else {
|
||||
@@ -120,25 +127,41 @@ export default class Tokens extends Controller {
|
||||
}
|
||||
|
||||
async validateSSO() {
|
||||
let redirectURL;
|
||||
if (Ember.testing) {
|
||||
redirectURL = this.router.currentURL;
|
||||
} else {
|
||||
redirectURL = new URL(window.location.toString());
|
||||
redirectURL.search = '';
|
||||
redirectURL = redirectURL.href;
|
||||
}
|
||||
|
||||
const res = await this.token.authorizedRequest(
|
||||
'/v1/acl/oidc/complete-auth',
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
AuthMethod: window.localStorage.getItem('nomadOIDCAuthMethod'),
|
||||
AuthMethodName: window.localStorage.getItem('nomadOIDCAuthMethod'),
|
||||
ClientNonce: window.localStorage.getItem('nomadOIDCNonce'),
|
||||
Code: this.code,
|
||||
State: this.state,
|
||||
RedirectURI: redirectURL,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
this.token.set('secret', data.ACLToken);
|
||||
this.verifyToken();
|
||||
this.clearTokenProperties();
|
||||
this.token.set('secret', data.SecretID);
|
||||
this.state = null;
|
||||
this.code = null;
|
||||
|
||||
// Refetch the token and associated policies
|
||||
this.get('token.fetchSelfTokenAndPolicies').perform().catch();
|
||||
|
||||
this.signInStatus = 'success';
|
||||
this.token.set('tokenNotFound', false);
|
||||
} else {
|
||||
this.state = 'failure';
|
||||
this.code = null;
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
class="button is-primary"
|
||||
onclick={{action "redirectToSSO" method}}
|
||||
type="button"
|
||||
>Sign in with with {{method.name}}
|
||||
>Sign in with {{method.name}}
|
||||
</button>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
@@ -443,7 +443,7 @@ export default function () {
|
||||
return JSON.stringify(findLeader(schema));
|
||||
});
|
||||
|
||||
this.get('/acl/tokens', function ({tokens}, req) {
|
||||
this.get('/acl/tokens', function ({ tokens }, req) {
|
||||
return this.serialize(tokens.all());
|
||||
});
|
||||
|
||||
@@ -548,9 +548,14 @@ export default function () {
|
||||
|
||||
this.delete('/acl/policy/:id', function (schema, request) {
|
||||
const { id } = request.params;
|
||||
schema.tokens.all().models.filter(token => token.policyIds.includes(id)).forEach(token => {
|
||||
token.update({ policyIds: token.policyIds.filter(pid => pid !== id) });
|
||||
});
|
||||
schema.tokens
|
||||
.all()
|
||||
.models.filter((token) => token.policyIds.includes(id))
|
||||
.forEach((token) => {
|
||||
token.update({
|
||||
policyIds: token.policyIds.filter((pid) => pid !== id),
|
||||
});
|
||||
});
|
||||
server.db.policies.remove(id);
|
||||
return '';
|
||||
});
|
||||
@@ -566,7 +571,6 @@ export default function () {
|
||||
description: Description,
|
||||
rules: Rules,
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
this.get('/regions', function ({ regions }) {
|
||||
@@ -979,26 +983,37 @@ export default function () {
|
||||
return schema.authMethods.all();
|
||||
});
|
||||
this.post('/acl/oidc/auth-url', (schema, req) => {
|
||||
const {AuthMethod, ClientNonce, RedirectUri, Meta} = JSON.parse(req.requestBody);
|
||||
return new Response(200, {}, {
|
||||
AuthURL: `/ui/oidc-mock?auth_method=${AuthMethod}&client_nonce=${ClientNonce}&redirect_uri=${RedirectUri}&meta=${Meta}`
|
||||
});
|
||||
const { AuthMethodName, ClientNonce, RedirectUri, Meta } = JSON.parse(
|
||||
req.requestBody
|
||||
);
|
||||
return new Response(
|
||||
200,
|
||||
{},
|
||||
{
|
||||
AuthURL: `/ui/oidc-mock?auth_method=${AuthMethodName}&client_nonce=${ClientNonce}&redirect_uri=${RedirectUri}&meta=${Meta}`,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Simulate an OIDC callback by assuming the code passed is the secret of an existing token, and return that token.
|
||||
this.post('/acl/oidc/complete-auth', function (schema, req) {
|
||||
const code = JSON.parse(req.requestBody).Code;
|
||||
const token = schema.tokens.findBy({
|
||||
id: code
|
||||
});
|
||||
|
||||
return new Response(200, {}, {
|
||||
ACLToken: token.secretId
|
||||
});
|
||||
}, {timing: 1000});
|
||||
|
||||
|
||||
this.post(
|
||||
'/acl/oidc/complete-auth',
|
||||
function (schema, req) {
|
||||
const code = JSON.parse(req.requestBody).Code;
|
||||
const token = schema.tokens.findBy({
|
||||
id: code,
|
||||
});
|
||||
|
||||
return new Response(
|
||||
200,
|
||||
{},
|
||||
{
|
||||
SecretID: token.secretId,
|
||||
}
|
||||
);
|
||||
},
|
||||
{ timing: 1000 }
|
||||
);
|
||||
|
||||
//#endregion SSO
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user