WIP: Got the SAML login working

TODO: Cleanup, remove hardcoded url.
This commit is contained in:
J Shamsul Bahri (jibone))
2020-09-04 13:56:54 +08:00
parent bd7e8cc78e
commit 1ae5a74c3a
25 changed files with 698 additions and 84 deletions
+69 -67
View File
@@ -28,72 +28,74 @@ sentry:
auth:
providers:
google:
development:
appOrigin: "http://localhost:3000/"
secure: false
clientId:
$secret:
env: AUTH_GOOGLE_CLIENT_ID
clientSecret:
$secret:
env: AUTH_GOOGLE_CLIENT_SECRET
github:
development:
appOrigin: "http://localhost:3000/"
secure: false
clientId:
$secret:
env: AUTH_GITHUB_CLIENT_ID
clientSecret:
$secret:
env: AUTH_GITHUB_CLIENT_SECRET
enterpriseInstanceUrl:
$secret:
env: AUTH_GITHUB_ENTERPRISE_INSTANCE_URL
gitlab:
development:
appOrigin: "http://localhost:3000/"
secure: false
clientId:
$secret:
env: AUTH_GITLAB_CLIENT_ID
clientSecret:
$secret:
env: AUTH_GITLAB_CLIENT_SECRET
audience:
$secret:
env: GITLAB_BASE_URL
# saml:
# google:
# development:
# entryPoint: "http://localhost:7001/"
# issuer: "passport-saml"
okta:
# appOrigin: 'http://localhost:3000/'
# secure: false
# clientId:
# $secret:
# env: AUTH_GOOGLE_CLIENT_ID
# clientSecret:
# $secret:
# env: AUTH_GOOGLE_CLIENT_SECRET
# github:
# development:
# appOrigin: 'http://localhost:3000/'
# secure: false
# clientId:
# $secret:
# env: AUTH_GITHUB_CLIENT_ID
# clientSecret:
# $secret:
# env: AUTH_GITHUB_CLIENT_SECRET
# enterpriseInstanceUrl:
# $secret:
# env: AUTH_GITHUB_ENTERPRISE_INSTANCE_URL
# gitlab:
# development:
# appOrigin: 'http://localhost:3000/'
# secure: false
# clientId:
# $secret:
# env: AUTH_GITLAB_CLIENT_ID
# clientSecret:
# $secret:
# env: AUTH_GITLAB_CLIENT_SECRET
# audience:
# $secret:
# env: GITLAB_BASE_URL
saml:
development:
appOrigin: "http://localhost:3000/"
secure: false
clientId:
$secret:
env: AUTH_OKTA_CLIENT_ID
clientSecret:
$secret:
env: AUTH_OKTA_CLIENT_SECRET
audience:
$secret:
env: AUTH_OKTA_AUDIENCE
oauth2:
development:
appOrigin: "http://localhost:3000/"
secure: false
clientId:
$secret:
env: AUTH_OAUTH2_CLIENT_ID
clientSecret:
$secret:
env: AUTH_OAUTH2_CLIENT_SECRET
authorizationURL:
$secret:
env: AUTH_OAUTH2_AUTH_URL
tokenURL:
$secret:
env: AUTH_OAUTH2_TOKEN_URL
entryPoint: 'https://sso.jumpcloud.com/saml2/backstage-test'
issuer: 'passport-saml'
# entryPoint: 'http://localhost:7001/'
# issuer: 'passport-saml'
# okta
# development:
# appOrigin: 'http://localhost:3000/'
# secure: false
# clientId:
# $secret:
# env: AUTH_OKTA_CLIENT_ID
# clientSecret:
# $secret:
# env: AUTH_OKTA_CLIENT_SECRET
# audience:
# $secret:
# env: AUTH_OKTA_AUDIENCE
# oauth2:
# development:
# appOrigin: 'http://localhost:3000/'
# secure: false
# clientId:
# $secret:
# env: AUTH_OAUTH2_CLIENT_ID
# clientSecret:
# $secret:
# env: AUTH_OAUTH2_CLIENT_SECRET
# authorizationURL:
# $secret:
# env: AUTH_OAUTH2_AUTH_URL
# tokenURL:
# $secret:
# env: AUTH_OAUTH2_TOKEN_URL
+4 -1
View File
@@ -33,7 +33,10 @@ const app = createApp({
components: {
SignInPage: props => {
return (
<SignInPage {...props} providers={['guest', 'custom', ...providers]} />
<SignInPage
{...props}
providers={['guest', 'custom', 'saml', ...providers]}
/>
);
},
},
+10
View File
@@ -38,6 +38,8 @@ import {
gitlabAuthApiRef,
storageApiRef,
WebStorage,
SamlAuth,
samlAuthApiRef,
} from '@backstage/core';
import {
@@ -139,6 +141,14 @@ export const apis = (config: ConfigApi) => {
}),
);
builder.add(
samlAuthApiRef,
SamlAuth.create({
apiOrigin: backendUrl,
basePath: '/auth/',
}),
);
builder.add(
techRadarApiRef,
new TechRadar({
+7
View File
@@ -19,6 +19,7 @@ import {
gitlabAuthApiRef,
oktaAuthApiRef,
githubAuthApiRef,
samlAuthApiRef,
} from '@backstage/core';
export const providers = [
@@ -46,4 +47,10 @@ export const providers = [
message: 'Sign In using Okta',
apiRef: oktaAuthApiRef,
},
{
id: 'saml-auth-provider',
title: 'SAML',
message: 'Sign In using SAML',
apiRef: samlAuthApiRef,
},
];
@@ -97,6 +97,21 @@ export type OAuthApi = {
logout(): Promise<void>;
};
/**
* This API provides access to SAML 2 credentials. Verify user access with identity provider.
*/
export type SamlApi = {
// Not sure what Promise call back should have.
getBackstageIdentity(
options?: AuthRequestOptions,
): Promise<BackstageIdentity | undefined>;
getProfile(options?: AuthRequestOptions): Promise<ProfileInfo | undefined>;
// Not sure if this is needed.
logout(): Promise<void>;
};
/**
* This API provides access to OpenID Connect credentials. It lets you request ID tokens,
* which can be passed to backend services to prove the user's identity.
@@ -273,3 +288,11 @@ export const oauth2ApiRef = createApiRef<
id: 'core.auth.oauth2',
description: 'Example of how to use oauth2 custom provider',
});
/**
* Provides authentication for saml based identity providers
*/
export const samlAuthApiRef = createApiRef<SamlApi>({
id: 'core.auth.saml',
description: 'provides authentication towards saml based provider',
});
@@ -19,3 +19,4 @@ export * from './gitlab';
export * from './google';
export * from './oauth2';
export * from './okta';
export * from './saml';
@@ -0,0 +1,126 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import SamlIcon from '@material-ui/icons/AcUnit';
import { SamlAuthConnector } from '../../../../lib/AuthConnector';
import { SessionManager } from '../../../../lib/AuthSessionManager/types';
import { Observable } from '../../../../types';
import {
ProfileInfo,
BackstageIdentity,
SessionState,
AuthRequestOptions,
SamlApi,
} from '../../../definitions/auth';
import { AuthProvider } from '../../../definitions';
import { SamlSession } from './types';
import {
SamlAuthSessionManager,
SamlAuthSessionStore,
} from '../../../../lib/AuthSessionManager';
type CreateOptions = {
apiOrigin: string;
basePath: string;
// oauthRequestApi?: OAuthRequestApi;
environment?: string;
provider?: AuthProvider & { id: string };
};
export type SamlAuthResponse = {
userId: string;
profile: ProfileInfo;
backstageIdentity: BackstageIdentity;
};
const DEFAULT_PROVIDER = {
id: 'saml',
title: 'SAML',
icon: SamlIcon,
};
class SamlAuth implements SamlApi {
static create({
apiOrigin,
basePath,
environment = 'development',
provider = DEFAULT_PROVIDER,
}: CreateOptions) {
// eslint-disable-next-line no-console
console.log('this is from SamlAuth');
const connector = new SamlAuthConnector<SamlSession>({
apiOrigin,
basePath,
environment,
provider,
});
const sessionManager = new SamlAuthSessionManager<SamlSession>({
connector,
});
const authSessionStore = new SamlAuthSessionStore<SamlSession>({
manager: sessionManager,
storageKey: 'samlSession',
});
// return new SamlAuth(authSessionStore);
return new SamlAuth(authSessionStore);
}
sessionState$(): Observable<SessionState> {
return this.sessionManager.sessionState$();
}
// constructor(private readonly sessionManager: any) {}
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor(private readonly sessionManager: SessionManager<SamlSession>) {
// eslint-disable-next-line no-console
console.log('this is the constructor');
}
async getBackstageIdentity(
options: AuthRequestOptions,
): Promise<BackstageIdentity | undefined> {
// eslint-disable-next-line no-console
console.log('===> Saml getBackstageIdentity()');
const session = await this.sessionManager.getSession(options);
// eslint-disable-next-line no-console
console.log('this this thish lkkdfkkfkfji');
// eslint-disable-next-line no-console
console.log(session);
return session?.backstageIdentity;
}
async getProfile(options: AuthRequestOptions = {}) {
// eslint-disable-next-line no-console
console.log('==> samlauth getprofile()');
const session = await this.sessionManager.getSession(options);
// eslint-disable-next-line no-console
console.log('+++ this is the session from getProfile()');
// eslint-disable-next-line no-console
console.log(session);
return session?.profile;
}
async logout() {
await this.sessionManager.removeSession();
}
}
export default SamlAuth;
@@ -0,0 +1,16 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { default as SamlAuth } from './SamlAuth';
@@ -0,0 +1,22 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ProfileInfo, BackstageIdentity } from '../../../definitions';
export type SamlSession = {
userId: string;
profile: ProfileInfo;
backstageIdentity: BackstageIdentity;
};
+4
View File
@@ -67,6 +67,10 @@ export class AppIdentity implements IdentityApi {
// This is indirectly called by the sign-in page to continue into the app.
setSignInResult(result: SignInResult) {
// eslint-disable-next-line no-console
console.log('this is from setSignInResult');
// eslint-disable-next-line no-console
console.log(result);
if (this.hasIdentity) {
return;
}
@@ -0,0 +1,105 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
AuthProvider,
ProfileInfo,
BackstageIdentity,
} from '../../apis/definitions';
import { AuthConnector } from './types';
import { showLoginPopup } from '../loginPopup';
const DEFAULT_BASE_PATH = '/api/auth';
type Options = {
apiOrigin?: string;
basePath?: string;
environment?: string;
provider: AuthProvider & { id: string };
};
export type SamlResponse = {
userId: string;
profile: ProfileInfo;
backstageIdentity: BackstageIdentity;
};
export class SamlAuthConnector<SamlResponse> implements AuthConnector<SamlResponse> {
private readonly apiOrigin: string;
private readonly basePath: string;
private readonly environment: string | undefined;
private readonly provider: AuthProvider & { id: string };
constructor(options: Options) {
const {
apiOrigin = window.location.origin,
basePath = DEFAULT_BASE_PATH,
environment,
provider,
} = options;
this.apiOrigin = apiOrigin;
this.basePath = basePath;
this.environment = environment;
this.provider = provider;
}
async createSession(): Promise<SamlResponse> {
// eslint-disable-next-line no-console
console.log('==> from SamlAuthConnector createSession');
const payload = await showLoginPopup({
url: 'http://localhost:7000/auth/saml/start', // FIXME: this should be from app.config or somewhere
name: 'SAML Login', // FIXME: change this to provider name? and not hardcode the name
origin: this.apiOrigin,
width: 450,
height: 730,
});
// eslint-disable-next-line no-console
console.log(payload);
return {
...payload,
id: payload.profile.email,
};
}
// TODO: do we need this for SAML?
async refreshSession(): Promise<any> {
// eslint-disable-next-line no-console
console.log('==> this is refresh session');
}
async removeSession(): Promise<void> {
// eslint-disable-next-line no-console
console.log('this removes the session');
const res = await fetch('http://localhost:7000/auth/saml/logout', {
method: 'POST',
headers: {
'x-requested-with': 'XMLHttpRequest',
},
credentials: 'include',
}).catch(error => {
throw new Error(`Logout request failed, ${error}`);
});
if (!res.ok) {
const error: any = new Error(`Logout request failed, ${res.statusText}`);
error.status = res.status;
throw error;
}
}
}
@@ -15,4 +15,5 @@
*/
export { DefaultAuthConnector } from './DefaultAuthConnector';
export { SamlAuthConnector } from './SamlAuthConnector';
export * from './types';
@@ -0,0 +1,64 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { SessionManager, GetSessionOptions } from './types';
import { SamlAuthConnector, SamlResponse } from '../AuthConnector/SamlAuthConnector';
import { SessionStateTracker } from './SessionStateTracker';
type Options = {
connector: SamlAuthConnector<SamlResponse>;
};
export class SamlAuthSessionManager<T> implements SessionManager<T> {
private readonly connector: SamlAuthConnector<SamlResponse>;
private readonly stateTracker = new SessionStateTracker();
private currentSession: any | undefined; // FIXME: proper typing here
constructor(options: Options) {
const { connector } = options;
this.connector = connector;
// this.helper = new SessionScopeHelper
}
async getSession(options: GetSessionOptions): Promise<T | undefined> {
// eslint-disable-next-line no-console
console.log('==> this is from SamlAuthSessionManager getSession()');
if (this.currentSession) {
return this.currentSession;
}
if (options.optional) {
return undefined;
}
this.currentSession = await this.connector.createSession();
this.stateTracker.setIsSignedIn(true);
return this.currentSession;
}
async removeSession() {
this.currentSession = undefined;
await this.connector.removeSession();
this.stateTracker.setIsSignedIn(false);
}
sessionState$() {
return this.stateTracker.sessionState$();
}
}
@@ -0,0 +1,96 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { SamlAuthSessionManager, GetSessionOptions } from './types';
type Options<T> = {
manager: SamlAuthSessionManager<T>;
storageKey: string;
};
export class SamlAuthSessionStore<T> implements SamlAuthSessionManager<T> {
private readonly manager: SamlAuthSessionManager<T>;
private readonly storageKey: string;
constructor(options: Options<T>) {
const { manager, storageKey } = options;
this.manager = manager;
this.storageKey = storageKey;
}
async getSession(options: GetSessionOptions): Promise<T | undefined> {
// eslint-disable-next-line no-console
console.log('==>> this is from SamlAuthSessionStore getSession()');
const session = this.loadSession();
if (session) {
return session!;
}
const newSession = await this.manager.getSession(options);
this.saveSession(newSession);
return newSession;
}
async removeSession() {
localStorage.removeItem(this.storageKey);
await this.manager.removeSession();
}
sessionState$() {
return this.manager.sessionState$();
}
private saveSession(session: T | undefined) {
if (session === undefined) {
localStorage.removeItem(this.storageKey);
} else {
localStorage.setItem(
this.storageKey,
JSON.stringify(session, (_key, value) => {
if (value instanceof Set) {
return {
__type: 'Set',
__value: Array.from(value),
};
}
return value;
}),
);
}
}
private loadSession(): T | undefined {
try {
const sessionJson = localStorage.getItem(this.storageKey);
if (sessionJson) {
const session = JSON.parse(sessionJson, (_key, value) => {
if (value?.__type === 'Set') {
return new Set(value.__value);
}
return value;
});
return session;
}
return undefined;
} catch (error) {
localStorage.removeItem(this.storageKey);
return undefined;
}
}
}
@@ -16,5 +16,7 @@
export { RefreshingAuthSessionManager } from './RefreshingAuthSessionManager';
export { StaticAuthSessionManager } from './StaticAuthSessionManager';
export { SamlAuthSessionManager } from './SamlAuthSessionManager';
export { AuthSessionStore } from './AuthSessionStore';
export { SamlAuthSessionStore } from './SamlAuthSessionStore';
export * from './types';
@@ -36,6 +36,13 @@ export type SessionManager<T> = {
sessionState$(): Observable<SessionState>;
};
// FIXME do we need this?
export type SamlAuthSessionManager<T> = {
getSession(options: GetSessionOptions): Promise<T | undefined>;
removeSession(): Promise<void>;
sessionState$(): Observable<SessionState>;
};
/**
* A function called to determine the scopes of a session.
*/
@@ -49,6 +49,12 @@ export function SidebarUserSettings() {
if (!sidebarOpen && open) setOpen(false);
}, [open, sidebarOpen]);
// FIXME: Change this and remove the session storage stuff
const handleLogout = () => {
identityApi.logout();
window.sessionStorage.clear();
};
return (
<>
<SidebarUserProfile open={open} setOpen={setOpen} />
@@ -91,7 +97,7 @@ export function SidebarUserSettings() {
<SidebarItem
icon={SignOutIcon}
text="Sign Out"
onClick={() => identityApi.logout()}
onClick={handleLogout}
/>
</Collapse>
</>
@@ -36,6 +36,11 @@ const Component: ProviderComponent = ({ config, onResult }) => {
instantPopup: true,
});
// eslint-disable-next-line no-console
console.log('====++++++++++++++++++++++++++> handleLogin for commonProvider');
// eslint-disable-next-line no-console
console.log(identity);
const profile = await authApi.getProfile();
onResult({
userId: identity!.id,
@@ -26,6 +26,7 @@ import { SignInConfig, IdentityProviders, SignInProvider } from './types';
import { commonProvider } from './commonProvider';
import { guestProvider } from './guestProvider';
import { customProvider } from './customProvider';
import { samlProvider } from './samlProvider';
const PROVIDER_STORAGE_KEY = '@backstage/core:SignInPage:provider';
@@ -41,6 +42,7 @@ const signInProviders: { [key: string]: SignInProvider } = {
guest: guestProvider,
custom: customProvider,
common: commonProvider,
saml: samlProvider,
};
function validateIDs(id: string, providers: SignInProviderType): void {
@@ -0,0 +1,92 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Grid, Typography, Button } from '@material-ui/core';
import { ProviderComponent, ProviderLoader, SignInProvider } from './types';
import { useApi, errorApiRef /* samlAuthApiRef */ } from '@backstage/core-api';
import { InfoCard } from '../InfoCard/InfoCard';
const Component: ProviderComponent = ({ onResult }) => {
// const samlApi = useApi(samlAuthApiRef);
const errorApi = useApi(errorApiRef);
const handleSSORedirect = () => {
// FIXME: this shoudl be from identity API or something.
window.open('http://localhost:7000/auth/saml/start');
};
const receiveMessage = (event: any) => {
// FIXME: Should use the backstage identity API and not create this session storage.
window.sessionStorage.setItem(
'helixSession',
JSON.stringify(event.data.response),
);
onResult({
userId: event.data.response.backstageIdentity,
profile: {
email: event.data.response.profile.email,
displayName: event.data.response.profile.displayName,
},
});
};
const handleLogin = async () => {
try {
// FIXME: this should be handle through backstage API or something.
handleSSORedirect();
window.addEventListener('message', receiveMessage, false);
} catch (error) {
errorApi.post(error);
}
};
return (
<Grid item>
<InfoCard
title="SAML"
actions={
<Button color="primary" variant="outlined" onClick={handleLogin}>
Sign In
</Button>
}
>
<Typography variant="body1">Sign In using SAML lolololol</Typography>
</InfoCard>
</Grid>
);
};
const loader: ProviderLoader = async () => {
// FIXME: should get the profile from identiy API not from storage session.
const sessionRaw = window.sessionStorage.getItem('helixSession');
if (!sessionRaw) {
return undefined;
}
const session = JSON.parse(sessionRaw);
return {
userId: session.backstageIdentity,
profile: {
email: session.profile.email,
displayName: session.profile.displayName,
},
};
};
export const samlProvider: SignInProvider = { Component, loader };
+5 -4
View File
@@ -24,18 +24,19 @@ import {
ProfileInfoApi,
BackstageIdentityApi,
SessionStateApi,
SamlApi,
} from '@backstage/core-api';
export type SignInConfig = {
id: string;
title: string;
message: string;
apiRef: ApiRef<
OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionStateApi
>;
apiRef:
| ApiRef<OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionStateApi>
| ApiRef<SamlApi>;
};
export type IdentityProviders = ('guest' | 'custom' | SignInConfig)[];
export type IdentityProviders = ('guest' | 'custom' | 'saml' | SignInConfig)[];
export type ProviderComponent = ComponentType<
SignInPageProps & { config: SignInConfig }
@@ -62,6 +62,7 @@ export const createAuthProviderRouter = (
for (const env of envs) {
const envConfig = providerConfig.getConfig(env);
console.log(envConfig);
const provider = factory(globalConfig, env, envConfig, logger, issuer);
if (provider) {
envProviders[env] = provider;
@@ -55,8 +55,21 @@ export class SamlAuthProvider implements AuthProviderRouteHandlers {
// for non-oauth auth flows.
// TODO: This flow doesn't issue an identity token that can be used to validate
// the identity of the user in other backends, which we need in some form.
console.log('===>');
console.log('===>');
console.log('===>');
console.log('===>');
console.log('===>');
console.log('===>');
console.log('===>');
console.log('===>');
console.log('===>');
console.log('===>');
console.log('===>');
console.log('===> SamlAuthProvider constructor');
console.log(profile);
done(undefined, {
userId: profile.ID!,
userId: profile.nameID!,
profile: {
email: profile.email!,
displayName: profile.displayName as string,
@@ -76,9 +89,9 @@ export class SamlAuthProvider implements AuthProviderRouteHandlers {
): Promise<void> {
try {
const {
response: { userId, profile },
response: { userId, profile },
} = await executeFrameHandlerStrategy<SamlInfo>(req, this.strategy);
const id = userId;
const idToken = await this.tokenIssuer.issueToken({
claims: { sub: id },
@@ -107,8 +120,14 @@ export class SamlAuthProvider implements AuthProviderRouteHandlers {
res.send('noop');
}
identifyEnv(): string | undefined {
return undefined;
identifyEnv(req: express.Request): string | undefined {
const reqEnv = req.query.env?.toString();
if (reqEnv) {
return reqEnv;
}
// FIXME : do we want to always to return 'development' ?
return 'development';
}
}
@@ -116,14 +116,14 @@ export class HigherOrderOperations implements HigherOrderOperation {
* Entities are read from their respective sources, are parsed and validated
* according to the entity policy, and get inserted or updated in the catalog.
* Entities that have disappeared from their location are left orphaned,
* without changes.
* without changes.i
*/
async refreshAllLocations(): Promise<void> {
const startTimestamp = new Date().valueOf();
this.logger.info('Beginning locations refresh');
// this.logger.info('Beginning locations refresh');
const locations = await this.locationsCatalog.locations();
this.logger.info(`Visiting ${locations.length} locations`);
// this.logger.info(`Visiting ${locations.length} locations`);
for (const { data: location } of locations) {
this.logger.debug(
+2 -3
View File
@@ -9848,9 +9848,8 @@ file-loader@^4.2.0:
loader-utils "^1.2.3"
schema-utils "^2.5.0"
"file-saver@github:eligrey/FileSaver.js#1.3.8":
file-saver@eligrey/FileSaver.js#1.3.8:
version "1.3.8"
uid e865e37af9f9947ddcced76b549e27dc45c1cb2e
resolved "https://codeload.github.com/eligrey/FileSaver.js/tar.gz/e865e37af9f9947ddcced76b549e27dc45c1cb2e"
file-system-cache@^1.0.5:
@@ -12977,7 +12976,7 @@ jspdf@1.5.3:
integrity sha512-J9X76xnncMw+wIqb15HeWfPMqPwYxSpPY8yWPJ7rAZN/ZDzFkjCSZObryCyUe8zbrVRNiuCnIeQteCzMn7GnWw==
dependencies:
canvg "1.5.3"
file-saver "github:eligrey/FileSaver.js#1.3.8"
file-saver eligrey/FileSaver.js#1.3.8
html2canvas "1.0.0-alpha.12"
omggif "1.0.7"
promise-polyfill "8.1.0"