Skip to content

Commit

Permalink
Merge pull request #107 from ymaheshwari1/feat/single-sign-in
Browse files Browse the repository at this point in the history
Implemented: support for SSO for apps using moqui login
  • Loading branch information
ymaheshwari1 authored May 23, 2024
2 parents 26e5d7e + f114909 commit bca3b06
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 17 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ VUE_APP_I18N_LOCALE=en
VUE_APP_I18N_FALLBACK_LOCALE=en
VUE_APP_LOCALES={"en": "English", "ja": "日本語", "es": "Español"}
VUE_APP_CURRENCY_FORMATS={"en": {"currency": {"style": "currency","currency": "USD"}}, "ja": {"currency": {"style": "currency", "currency": "JPY"}}, "es": {"currency": {"style": "currency","currency": "ESP"}}}
VUE_APP_DEFAULT_ALIAS=
VUE_APP_DEFAULT_ALIAS=
VUE_APP_MAARG_LOGIN=["order-routing"]
23 changes: 23 additions & 0 deletions src/assets/images/OrderRouting.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
"Logout": "Logout",
"Logging out...": "Logging out...",
"Next": "Next",
"Not configured": "Not configured",
"OMS": "OMS",
"Password": "Password",
"Please fill in the OMS": "Please fill in the OMS",
"Please fill in the user details": "Please fill in the user details",
"Processing": "Processing",
"Something went wrong while login. Please contact administrator.": "Something went wrong while login. Please contact administrator.",
"Sorry, your username or password is incorrect. Please try again.": "Sorry, your username or password is incorrect. Please try again.",
"This application is not enabled for your account": "This application is not enabled for your account",
"Username": "Username"
}
8 changes: 7 additions & 1 deletion src/store/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export const useAuthStore = defineStore('authStore', {
value: '',
expiration: undefined
},
redirectUrl: ''
redirectUrl: '',
maargOms: ''
}),
getters: {
isAuthenticated: (state) => {
Expand All @@ -32,6 +33,7 @@ export const useAuthStore = defineStore('authStore', {
return baseURL.startsWith('http') ? baseURL.includes('/api') ? baseURL : `${baseURL}/api/` : `https://${baseURL}.hotwax.io/api/`
},
getRedirectUrl: (state) => state.redirectUrl,
getMaargOms: (state) => state.maargOms
},
actions: {
setOMS(oms: string) {
Expand Down Expand Up @@ -103,6 +105,7 @@ export const useAuthStore = defineStore('authStore', {
expiration: undefined
}
this.redirectUrl = ''
this.maargOms = ''
updateToken('');
emitter.emit('dismissLoader')
},
Expand All @@ -115,6 +118,9 @@ export const useAuthStore = defineStore('authStore', {
},
async setCurrent(current: any) {
this.current = current
},
async setMaargInstance(url: string) {
this.maargOms = url
}
},
persist: true
Expand Down
7 changes: 6 additions & 1 deletion src/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ const showToast = async (message: string) => {
return toast.present();
}

export { showToast }
const isMaargLogin = (handle: string) => {
const maargLoginApps = JSON.parse(process.env.VUE_APP_MAARG_LOGIN ? process.env.VUE_APP_MAARG_LOGIN : [])
return maargLoginApps.some((appName: string) => handle.includes(appName))
}

export { isMaargLogin, showToast }
36 changes: 30 additions & 6 deletions src/views/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,20 @@
<div class="type" v-for="category in Object.keys(appCategory)" :key="category">
<h3>{{ category }}</h3>
<div class="apps">
<ion-card button class="app" v-for="app in appCategory[category]" :key="app.handle" :href="scheme + app.handle + domain + (authStore.isAuthenticated ? `/login?oms=${authStore.getOMS.startsWith('http') ? authStore.getOMS.includes('/api') ? authStore.getOMS : `${authStore.getOMS}/api/` : authStore.getOMS}&token=${authStore.token.value}&expirationTime=${authStore.token.expiration}` : '')">
<ion-card button class="app" v-for="app in appCategory[category]" :key="app.handle" :disabled="authStore.isAuthenticated && isMaargLogin(app.handle) && !authStore.getMaargOms" @click.stop="generateAppLink(app)">
<div class="app-icon ion-padding">
<img :src="app.resource" />
</div>
<ion-card-header class="app-content">
<ion-card-title color="text-medium">{{ app.name }}</ion-card-title>
<ion-buttons class="app-links">
<ion-button color="medium" :href="scheme + app.handle + devHandle + domain + (authStore.isAuthenticated ? `/login?oms=${authStore.getOMS.startsWith('http') ? authStore.getOMS.includes('/api') ? authStore.getOMS : `${authStore.getOMS}/api/` : authStore.getOMS}&token=${authStore.token.value}&expirationTime=${authStore.token.expiration}` : '')">
<ion-badge class="ion-margin" color="medium" v-if="authStore.isAuthenticated && isMaargLogin(app.handle) && !authStore.getMaargOms">
{{ translate("Not configured") }}
</ion-badge>
<ion-buttons class="app-links" v-else>
<ion-button color="medium" @click.stop="generateAppLink(app, devHandle)">
<ion-icon slot="icon-only" :icon="codeWorkingOutline" />
</ion-button>
<ion-button color="medium" :href="scheme + app.handle + uatHandle + domain + (authStore.isAuthenticated ? `/login?oms=${authStore.getOMS.startsWith('http') ? authStore.getOMS.includes('/api') ? authStore.getOMS : `${authStore.getOMS}/api/` : authStore.getOMS}&token=${authStore.token.value}&expirationTime=${authStore.token.expiration}` : '')">
<ion-button color="medium" @click.stop="generateAppLink(app, uatHandle)">
<ion-icon slot="icon-only" :icon="shieldHalfOutline" />
</ion-button>
</ion-buttons>
Expand All @@ -60,7 +63,8 @@
</template>

<script lang="ts">
import {
import {
IonBadge,
IonButton,
IonButtons,
IonCard,
Expand All @@ -86,10 +90,13 @@ import {
import { useAuthStore } from '@/store/auth';
import { useRouter } from "vue-router";
import { goToOms } from '@hotwax/dxp-components'
import { isMaargLogin } from '@/util';
import { translate } from '@/i18n';
export default defineComponent({
name: 'Home',
components: {
IonBadge,
IonButton,
IonButtons,
IonCard,
Expand Down Expand Up @@ -125,6 +132,10 @@ export default defineComponent({
if (this.authStore.isAuthenticated) {
await this.authStore.logout()
}
},
generateAppLink(app: any, appEnvironment = '') {
const oms = isMaargLogin(app.handle) ? this.authStore.getMaargOms : this.authStore.getOMS;
window.location.href = this.scheme + app.handle + appEnvironment + this.domain + (this.authStore.isAuthenticated ? `/login?oms=${oms.startsWith('http') ? isMaargLogin(app.handle) ? oms : oms.includes('/api') ? oms : `${oms}/api/` : oms}&token=${this.authStore.token.value}&expirationTime=${this.authStore.token.expiration}${isMaargLogin(this.authStore.getRedirectUrl) ? '&omsRedirectionUrl=' + this.authStore.getOMS : ''}` : '')
}
},
setup() {
Expand Down Expand Up @@ -175,7 +186,7 @@ export default defineComponent({
handle: 'import',
name: 'Import',
resource: require('../assets/images/Import.svg'),
type: 'Workflow'
type: 'Administration'
}, {
handle: 'users',
name: 'Users',
Expand All @@ -186,6 +197,11 @@ export default defineComponent({
name: 'Facilities',
resource: require('../assets/images/Facilities.svg'),
type: 'Administration'
}, {
handle: 'order-routing',
name: 'Order Routing',
resource: require('../assets/images/OrderRouting.svg'),
type: 'Workflow'
}]
const appCategory = appInfo.reduce((obj: any, app: any) => {
Expand All @@ -210,6 +226,7 @@ export default defineComponent({
devHandle,
domain,
goToOms,
isMaargLogin,
lockClosedOutline,
hardwareChipOutline,
openOutline,
Expand All @@ -218,6 +235,7 @@ export default defineComponent({
router,
scheme,
shieldHalfOutline,
translate,
uatHandle
}
}
Expand Down Expand Up @@ -286,6 +304,7 @@ export default defineComponent({
ion-card-header {
text-align: center;
padding-bottom: 0;
align-items: center;
}
ion-card-title {
Expand All @@ -296,6 +315,11 @@ export default defineComponent({
.app-links {
justify-content: center;
}
.card-disabled {
opacity: 0.6;
}
@media only screen and (min-width: 768px) {
.app:hover {
box-shadow: rgb(0 0 0 / 26%) 0px 3px 17px -2px, rgb(0 0 0 / 14%) 0px 2px 6px 0px, rgb(0 0 0 / 12%) 0px 1px 12px 0px;
Expand Down
34 changes: 26 additions & 8 deletions src/views/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ import Logo from '@/components/Logo.vue';
import { arrowForwardOutline, gridOutline } from 'ionicons/icons'
import { UserService } from "@/services/UserService";
import { translate } from "@/i18n";
import { showToast } from "@/util";
import { isMaargLogin, showToast } from "@/util";
import { hasError } from "@hotwax/oms-api";
export default defineComponent({
Expand Down Expand Up @@ -128,7 +128,8 @@ export default defineComponent({
// logout from Launchpad if logged out from the app
if (this.$route.query?.isLoggedOut === 'true') {
// We will already mark the user as unuauthorised when log-out from the app
this.authStore.logout({ isUserUnauthorised: true })
// For the case of apps using maarg login, we will call the logout api from launchpad
isMaargLogin(this.$route.query.redirectUrl as string) ? await this.authStore.logout() : await this.authStore.logout({ isUserUnauthorised: true })
}
// fetch login options only if OMS is there as API calls require OMS
Expand All @@ -154,8 +155,7 @@ export default defineComponent({
// if a session is already active, login directly in the app
if (this.authStore.isAuthenticated) {
if(this.authStore.getRedirectUrl) {
const omsUrl = this.authStore.oms.startsWith('http') ? this.authStore.oms.includes('/api') ? this.authStore.oms : `${this.authStore.oms}/api/` : this.authStore.oms
window.location.href = `${this.authStore.getRedirectUrl}?oms=${omsUrl}&token=${this.authStore.token.value}&expirationTime=${this.authStore.token.expiration}`
this.generateRedirectionLink();
} else {
this.router.push('/')
}
Expand Down Expand Up @@ -229,6 +229,7 @@ export default defineComponent({
const resp = await UserService.checkLoginOptions()
if (!hasError(resp)) {
this.loginOption = resp.data
await this.authStore.setMaargInstance(resp.data.maargInstanceUrl)
}
} catch (error) {
console.error(error)

Check warning on line 235 in src/views/Login.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

Unexpected console statement

Check warning on line 235 in src/views/Login.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / build_and_deploy

Unexpected console statement

Check warning on line 235 in src/views/Login.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

Unexpected console statement
Expand All @@ -244,8 +245,7 @@ export default defineComponent({
try {
await this.authStore.login(username.trim(), password)
if (this.authStore.getRedirectUrl) {
const omsUrl = this.authStore.oms.startsWith('http') ? this.authStore.oms.includes('/api') ? this.authStore.oms : `${this.authStore.oms}/api/` : this.authStore.oms
window.location.href = `${this.authStore.getRedirectUrl}?oms=${omsUrl}&token=${this.authStore.token.value}&expirationTime=${this.authStore.token.expiration}`
this.generateRedirectionLink()
} else {
// All the failure cases are handled in action, if then block is executing, login is successful
this.username = ''
Expand All @@ -261,8 +261,7 @@ export default defineComponent({
const { token, expirationTime } = this.$route.query as any
await this.authStore.samlLogin(token, expirationTime)
if (this.authStore.getRedirectUrl) {
const omsUrl = this.authStore.oms.startsWith('http') ? this.authStore.oms.includes('/api') ? this.authStore.oms : `${this.authStore.oms}/api/` : this.authStore.oms
window.location.href = `${this.authStore.getRedirectUrl}?oms=${omsUrl}&token=${this.authStore.token.value}&expirationTime=${this.authStore.token.expiration}`
this.generateRedirectionLink();
} else {
this.router.push('/')
}
Expand All @@ -274,8 +273,13 @@ export default defineComponent({
async basicLogin() {
try {
const { oms, token, expirationTime } = this.$route.query as any
// Clear the previously stored oms and token when having oms and token in the URL
await this.authStore.setToken('', '')
await this.authStore.setOMS(oms);
// checking for login options as we need to get maarg instance URL for accessing specific apps
await this.fetchLoginOptions()
// Setting token previous to getting user-profile, if not then the client method honors the state token
await this.authStore.setToken(token, expirationTime)
Expand All @@ -286,6 +290,20 @@ export default defineComponent({
console.error("error: ", error);

Check warning on line 290 in src/views/Login.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

Unexpected console statement

Check warning on line 290 in src/views/Login.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / build_and_deploy

Unexpected console statement

Check warning on line 290 in src/views/Login.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

Unexpected console statement
}
this.router.replace('/')
},
generateRedirectionLink() {
let omsUrl = ''
if(isMaargLogin(this.authStore.getRedirectUrl)) {
if(this.authStore.getMaargOms) omsUrl = this.authStore.getMaargOms
else {
showToast(translate("This application is not enabled for your account"))
this.router.push("/")
return;
}
}
omsUrl = omsUrl ? omsUrl : this.authStore.oms.startsWith('http') ? this.authStore.oms.includes('/api') ? this.authStore.oms : `${this.authStore.oms}/api/` : this.authStore.oms
window.location.href = `${this.authStore.getRedirectUrl}?oms=${omsUrl}&token=${this.authStore.token.value}&expirationTime=${this.authStore.token.expiration}${isMaargLogin(this.authStore.getRedirectUrl) ? '&omsRedirectionUrl=' + this.authStore.oms : ''}`
}
},
setup () {
Expand Down

0 comments on commit bca3b06

Please sign in to comment.