1.0.0 • Published 3 years ago

pgm-auth v1.0.0

Weekly downloads
-
License
ISC
Repository
-
Last release
3 years ago

Auth System

This plug-in is designed to be easy-to-use client-side authentication using AWS Cognito + Amplify AUTH API with Vuetify UI components.

It will create a session with cognito for the user if they are in the pool, refresh the token and keep the session active. The token will be set as an axios auth header with the prefix "Cognito ".

New users must access their account and reset their password within 14* days to avoid their account being locked. If they fail to do this within the allotted time period, we currently do not have a way implemented to reset their account. You must delete and recreate the user.

Internal company users can continue to sign-in through Azure or login with cognito if needed (i.e. Azure goes down); a user account with "external_provider" will be created. Internal users using email + password will need to be/have been imported to the user pool; this will be two users within cognito, matching one in the database.

Region - "us-east-1"

Adding users to Cognito user pool

Users cannot sign themselves up with this tool.

Creating users with current pool settings

  • set the username as the user email, select "Send an invitation to this new user?"
  • no phone number needed, unselect "Mark phone number as verified?"
  • set user email, select "Mark email as verified?"

Importing users - todo

Requirements

  • Vue + Vuetify
  • AWS Credentials - secret access key and access key id
  • AWS Amplify
    • npm install -g @aws-amplify/cli
    • npm install aws-amplify
    • app - AWS amplify -> kwikcatclient -> backend environments -> kktk
  • AWS Cognito
    • User Pool - "kktkpool-kktk"
      • user pool Web App Client (app_clientWeb) (NO SECRET set on creation)
  • Optional - Federated Sign in (SAML) (azure ad)
    • azure app - Azure Portal -> Azure Active Directory -> App Registrations -> cognito-tk
    • cognito user pool Domain Name set

Federated Sign In

Azure:

Azure Portal -> Azure Active Directory -> App Registrations ->

  • Click "Endpoints" and copy "Federation metadata document"
  • New Registration ->
    • Add "Application ID URI" as "urn:amazon:cognito:sp:COGNITO POOL ID"
  • new app/ cognito-tk -> Authentication
    • Web platform with the Redirect URI as "FULL COGNITO DOMAIN NAME/saml2/idpresponse"
Cognito:

Federation ->

  • Identity Providers -> SAML
    • Enter "Federation metadata document" and the provider name with "Enable IdP sign out flow" checked, we are using "Azure"
  • Attribute Mapping -> SAML -> "Azure"

App Integration -> App Client Settings -> app_clientWeb

From there you can launch Hosted UI to test if it's all working.

App

Amplify CLI

https://docs.amplify.aws/lib/auth/getting-started/q/platform/js

** You should use the CLI anytime a Cognito Pool ID OR "App Client" ID Changes if possible BE CAREFUL editting aws-exports.js manually. It will be overwritten when someone uses the CLI.

Be sure to check https://docs.amplify.aws/cli/reference/files#amplifyconfig on what files to commit. Don't commit aws-exports, instead update main.js Amplify.Configure for user pool related config.

# install
npm install -g @aws-amplify/cli 

# pull OUR AMPLIFY APP
amplify pull --appId d18naine1f4qwi --envName kktk

# configure/sign in to AWS
amplify configure


# after install, run in project root
amplify init

# Unlink existing auth
amplify remove auth

# Create new Amplify-managed auth resources (create new user pool)
amplify add auth

# Update Amplify-managed auth resources (edit user pool, federation)
amplify update auth

# Use existing user pool
amplify import auth

# AFTER doing any of the above 4:
amplify push

amplify status

Using the CLI, you will be able to create all the necessary requirements to begin your authentication project (amplify app, cognito user+identity pool) or have the ability to set up a pre-existing project.

Quickstart

Step 1: Add plugin to /src/plugins/

Step 2: Add necessary imports to main.js. This will make the auth plugin and UI components (or simply auth) globally available

...
// Plug-in importing
import {DjangoAuth} from '@/auth'

// Dependencies
import Amplify from 'aws-amplify'

// AWS credentials
Amplify.configure({
  Auth: {
    region: 'us-east-1',
    userPoolWebClientId: '4qnhq21pi6h1khdlni88vjpp45',
    userPoolId: 'us-east-1_pr3KafRJD',
    oauth: {
      domain: 'pgm.auth.us-east-1.amazoncognito.com',
      scope: [
        'email',
        'openid',
        'profile',
        'aws.cognito.signin.user.admin'
      ],
      redirectSignIn: 'http://localhost:8001/',
      redirectSignOut: 'http://localhost:8001/',
      responseType: 'code'
    }
  }
})

Vue.use(DjangoAuth)

new Vue({})
...

Step 3: Wrap plugin and include in views

You can chose to include this in a dialog wrapper component and include in App.vue

This method was chosen for UI container flexibility (dialog, page, etc)

1 App Specific Wrapper (login)

Example dialog component

<template>
  <v-dialog
    persistent
    max-width="450"
    v-model="$store.getters.displayingLoginDialog"
    @input="$emit('input', $event)"
  >
    <auth-card
      :value="$store.getters.displayingLoginDialog"
      @input="$store.commit('setLoginDialog', $event)"
      @authenticated="authenticated"
    />
  </v-dialog>
</template>

<script>
import AuthCard from '../plugins/auth/AuthCard.vue'
export default {
  components: { AuthCard },
  name: 'AuthWrapper'
  methods: {
    // Handle APP SPECIFIC user fetching & rerouting after success
    authenticated () {
      this.$store.dispatch('getUser').then(r => {
        if (r) {
          this.$store.commit('setLoginDialog', false)
          this.$router.push({ name: 'dashboard' })
        }
      })
    }
  }
}
</script>
4 Login/Logout NavigationButtons.vue
//  if not authenticated, allow login
<v-btn
  text
  v-if="!$auth.isAuthenticated"
  @click="$store.commit('setLoginDialog', !$store.getters.displayingLoginDialog)"
>
  Login
</v-btn>

// else logout
<v-list-item
  @click="logout"
>
  <v-list-item-title>
    Logout
  </v-list-item-title>
</v-list-item>

// script
methods: {
  // logout
  logout () {
    // log out cognito session
    this.$auth.logout().then(() => {
      // handle APP SPECIFIC user state
      this.$store.dispatch('logout')
      // return to home back
      if (this.$route.name !== 'home') this.$router.push({ name: 'home' })
    })
  }
}
5 App.vue
// APP SPECIFIC template
<login
  :value="$store.getters.displayingLoginDialog"
  @input="$store.commit('setLoginDialog', $event)"
/>

Step 6: Persist user state

We handle this in our router by using the router.beforeEach route guard + auth.isAuthenticated()

import {tokenAuth} from "@/plugins/auth";

const auth = tokenAuth()

router.beforeEach(async (to, from, next) => {
  // try to get current session and user
  if (!auth.isAuthenticated || (auth.isAuthenticated && !store.getters.currentUser)) {
    try {
      await auth.activeSession().then(() => {
        store.dispatch('getUser').then(() => {
          next()
        })
      })
      return
    } catch (err) {}
  }

  next()
})

User flows

Unauthenticated user

User initial login

  • Users will receive an email with their login email and a temporary password on account creation
  • User authentication successful, but the account requires a new password
  • Returns:

    {
      ChallengeName: "NEW_PASSWORD_REQUIRED",
      ChallengeParameters: {
        requiredAttributes: "[]",
        userAttributes: "{\"email_verified\":\"true\",\"email\":\"{useremail}\"}"
      },
      Session: ""
    }
    • Users will enter and confirm a new password
    • Returns authentication results including a token and continues with login

Login

external user/traditional email + password sign in
  • Sends email & password to AWS to authenticate a user

  • If successful, reroutes user to dashboard, returns:

    {
      Credentials: {
        AccessKeyId: ""
        Expiration: "
        SecretKey: ""
        SessionToken: ""
      },
      IdentityId: ""
    }
  • If unsuccessful, set error message

internal user
  • Can choose between traditional sign in, or use Microsoft Azure AD federated sign-in

Password reset

  • user enters email, and requests code
  • user then will enter the code, a new and confirmation password, returns authentication results and continues with login

  • You can also reset a users password from the user pool if they have logged in prior (not a first time login)

Authenticated user

Logout

  • User clicks logout, their session is ended in cognito, user & session cleared in app state

Update Password

  • User enters old and new passwords and attempts to change password

  • If failed, sets error message

User Creation

  1. Create cognito users directly in the user pool by selecting "Create User" and setting the user email as username and email field. This is ideal for users that are pre-existing in our Database User Table or staff accounts.
  2. By a high level "admin" employee (must have KwikCat|kk profile|Add KK Profile permission) within the KWIKCAT-CLIENT project. This is ideal for "vendor" accounts. We use boto3 in our api for the account creation at this level. See kwikcat-client/src/components/AddUser

Components

AuthCard.vue

Primary auth component that wraps the other components for a seamless auth flow

components/SignIn.vue

User login fields and signin functionality

components/PasswordReset.vue

Provides logged-out user password reset functionality

components/UpdatePassword.vue

Provides fields for old password and new password for logged-in user password updating

components/PasswordFields.vue

Reusable New Password and Confirm Password fields

Resources

internal
aws