github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/controllers/settings/tokens.js (about)

     1  // @ts-check
     2  import { inject as service } from '@ember/service';
     3  import { reads } from '@ember/object/computed';
     4  import Controller from '@ember/controller';
     5  import { getOwner } from '@ember/application';
     6  import { alias } from '@ember/object/computed';
     7  import { action } from '@ember/object';
     8  import classic from 'ember-classic-decorator';
     9  import { tracked } from '@glimmer/tracking';
    10  import Ember from 'ember';
    11  
    12  @classic
    13  export default class Tokens extends Controller {
    14    @service token;
    15    @service store;
    16    @service router;
    17  
    18    queryParams = ['code', 'state'];
    19  
    20    @reads('token.secret') secret;
    21  
    22    /**
    23     * @type {(null | "success" | "failure")} signInStatus
    24     */
    25    @tracked
    26    signInStatus = null;
    27  
    28    @alias('token.selfToken') tokenRecord;
    29  
    30    resetStore() {
    31      this.store.unloadAll();
    32    }
    33  
    34    @action
    35    clearTokenProperties() {
    36      this.token.setProperties({
    37        secret: undefined,
    38        tokenNotFound: false,
    39      });
    40      this.signInStatus = null;
    41      // Clear out all data to ensure only data the anonymous token is privileged to see is shown
    42      this.resetStore();
    43      this.token.reset();
    44      this.store.findAll('auth-method');
    45    }
    46  
    47    get authMethods() {
    48      return this.store.peekAll('auth-method');
    49    }
    50  
    51    @action
    52    verifyToken() {
    53      const { secret } = this;
    54      this.clearTokenProperties();
    55      const TokenAdapter = getOwner(this).lookup('adapter:token');
    56  
    57      this.set('token.secret', secret);
    58      this.set('secret', null);
    59  
    60      TokenAdapter.findSelf().then(
    61        () => {
    62          // Clear out all data to ensure only data the new token is privileged to see is shown
    63          this.resetStore();
    64  
    65          // Refetch the token and associated policies
    66          this.get('token.fetchSelfTokenAndPolicies').perform().catch();
    67  
    68          this.signInStatus = 'success';
    69          this.token.set('tokenNotFound', false);
    70        },
    71        () => {
    72          this.set('token.secret', undefined);
    73          this.signInStatus = 'failure';
    74        }
    75      );
    76    }
    77  
    78    // Generate a 20-char nonce, using window.crypto to
    79    // create a sufficiently-large output then trimming
    80    generateNonce() {
    81      let randomArray = new Uint32Array(10);
    82      crypto.getRandomValues(randomArray);
    83      return randomArray.join('').slice(0, 20);
    84    }
    85  
    86    @action redirectToSSO(method) {
    87      const provider = method.name;
    88      const nonce = this.generateNonce();
    89  
    90      window.localStorage.setItem('nomadOIDCNonce', nonce);
    91      window.localStorage.setItem('nomadOIDCAuthMethod', provider);
    92  
    93      method
    94        .getAuthURL({
    95          AuthMethod: provider,
    96          ClientNonce: nonce,
    97          RedirectUri: Ember.testing
    98            ? this.router.currentURL
    99            : window.location.toString(),
   100        })
   101        .then(({ AuthURL }) => {
   102          if (Ember.testing) {
   103            this.router.transitionTo(AuthURL.split('/ui')[1]);
   104          } else {
   105            window.location = AuthURL;
   106          }
   107        });
   108    }
   109  
   110    @tracked code = null;
   111    @tracked state = null;
   112  
   113    get isValidatingToken() {
   114      if (this.code && this.state === 'success') {
   115        this.validateSSO();
   116        return true;
   117      } else {
   118        return false;
   119      }
   120    }
   121  
   122    async validateSSO() {
   123      const res = await this.token.authorizedRequest(
   124        '/v1/acl/oidc/complete-auth',
   125        {
   126          method: 'POST',
   127          body: JSON.stringify({
   128            AuthMethod: window.localStorage.getItem('nomadOIDCAuthMethod'),
   129            ClientNonce: window.localStorage.getItem('nomadOIDCNonce'),
   130            Code: this.code,
   131            State: this.state,
   132          }),
   133        }
   134      );
   135  
   136      if (res.ok) {
   137        const data = await res.json();
   138        this.token.set('secret', data.ACLToken);
   139        this.verifyToken();
   140        this.state = null;
   141        this.code = null;
   142      } else {
   143        this.state = 'failure';
   144        this.code = null;
   145      }
   146    }
   147  
   148    get SSOFailure() {
   149      return this.state === 'failure';
   150    }
   151  
   152    get canSignIn() {
   153      return !this.tokenRecord || this.tokenRecord.isExpired;
   154    }
   155  
   156    get shouldShowPolicies() {
   157      return this.tokenRecord;
   158    }
   159  }