Skip to content

Commit

Permalink
Added keycloak startegy
Browse files Browse the repository at this point in the history
  • Loading branch information
samarpan-b committed Jul 15, 2020
1 parent a9988b2 commit c2f91ad
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 63 deletions.
121 changes: 65 additions & 56 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@
],
"peerDependencies": {
"@loopback/boot": "^2.1.2",
"@loopback/context": "^3.6.0",
"@loopback/core": "^2.4.2",
"@loopback/rest": "^3.3.2"
},
"dependencies": {
"@loopback/core": "^2.7.0",
"@exlinc/keycloak-passport": "^1.0.2",
"@loopback/context": "^3.9.2",
"@loopback/core": "^2.9.1",
"passport": "^0.4.1",
"passport-azure-ad": "^4.2.1",
"passport-google-oauth20": "^2.0.0",
Expand All @@ -63,7 +63,6 @@
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@loopback/boot": "^2.3.1",
"@loopback/build": "^5.4.1",
"@loopback/context": "^3.8.1",
"@loopback/metadata": "^2.1.5",
"@loopback/rest": "^5.0.1",
"@loopback/testlab": "^3.1.5",
Expand All @@ -77,7 +76,7 @@
"@types/passport-http-bearer": "^1.0.35",
"@types/passport-local": "^1.0.33",
"@types/passport-oauth2-client-password": "^0.1.2",
"lodash": "^4.17.15",
"lodash": "^4.17.19",
"nyc": "^15.0.1",
"source-map-support": "^0.5.19",
"ts-node": "^8.10.1",
Expand Down
1 change: 1 addition & 0 deletions src/strategies/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './client-auth-strategy.provider';
export * from './user-auth-strategy.provider';
export * from './passport';
export * from './types';
11 changes: 10 additions & 1 deletion src/strategies/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import {BearerStrategyFactory} from './passport/passport-bearer';
import {ResourceOwnerPasswordStrategyFactory} from './passport/passport-resource-owner-password';
import {ClientPasswordStrategyFactory} from './passport/passport-client-password/client-password-strategy-factory-provider';
import {GoogleAuthStrategyFactoryProvider} from './passport/passport-google-oauth2';
import {VerifyFunction} from './passport';
import {KeycloakStrategyFactoryProvider} from './passport/passport-keycloak';
import {AzureADAuthStrategyFactoryProvider} from './passport/passport-azure-ad';
import {VerifyFunction} from './types';

export namespace Strategies {
export namespace Passport {
Expand Down Expand Up @@ -55,5 +56,13 @@ export namespace Strategies {
export const AZURE_AD_VERIFIER = BindingKey.create<
VerifyFunction.AzureADAuthFn
>('sf.passport.verifier.azureAd');

// Passport-keycloak strategy
export const KEYCLOAK_STRATEGY_FACTORY = BindingKey.create<
KeycloakStrategyFactoryProvider
>('sf.passport.strategyFactory.keycloak');
export const KEYCLOAK_VERIFIER = BindingKey.create<
VerifyFunction.KeycloakAuthFn
>('sf.passport.verifier.keycloak');
}
}
2 changes: 1 addition & 1 deletion src/strategies/passport/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ export * from './passport-bearer';
export * from './passport-client-password';
export * from './passport-local';
export * from './passport-resource-owner-password';
export * from '../types';
export * from './passport-keycloak';
2 changes: 2 additions & 0 deletions src/strategies/passport/passport-keycloak/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './keycloak-strategy-factory-provider';
export * from './keycloak-verify.provider';
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {inject, Provider} from '@loopback/core';
import {HttpErrors} from '@loopback/rest';

import {AuthErrorKeys} from '../../../error-keys';
import {IAuthUser} from '../../../types';
import {Strategies} from '../../keys';
import {KeycloakProfile, VerifyFunction} from '../../types';

export const KeycloakStrategy = require('@exlinc/keycloak-passport');

export interface KeycloakStrategyFactory {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(options: any): typeof KeycloakStrategy;
}

export class KeycloakStrategyFactoryProvider
implements Provider<KeycloakStrategyFactory> {
constructor(
@inject(Strategies.Passport.KEYCLOAK_VERIFIER)
private readonly verifierKeycloak: VerifyFunction.KeycloakAuthFn,
) {}

value(): KeycloakStrategyFactory {
return (options) => this.getGoogleAuthStrategyVerifier(options);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
getGoogleAuthStrategyVerifier(options: any): typeof KeycloakStrategy {
return new KeycloakStrategy(
options,
async (
accessToken: string,
refreshToken: string,
profile: KeycloakProfile,
cb: (err?: string | Error, user?: IAuthUser) => void,
) => {
try {
const user = await this.verifierKeycloak(
accessToken,
refreshToken,
profile,
cb,
);
if (!user) {
throw new HttpErrors.Unauthorized(AuthErrorKeys.InvalidCredentials);
}
cb(undefined, user);
} catch (err) {
cb(err);
}
},
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {Provider} from '@loopback/context';
import {HttpErrors} from '@loopback/rest';

import {KeycloakProfile, VerifyFunction} from '../../types';

/**
* A provider for default implementation of VerifyFunction.LocalPasswordFn
*
* It will just throw an error saying Not Implemented
*/
export class KeycloakVerifyProvider
implements Provider<VerifyFunction.KeycloakAuthFn> {
constructor() {}

value(): VerifyFunction.KeycloakAuthFn {
return async (
accessToken: string,
refreshToken: string,
profile: KeycloakProfile,
cb: (err?: string | Error, user?: KeycloakProfile) => void,
) => {
throw new HttpErrors.NotImplemented(
`VerifyFunction.KeycloakAuthFn is not implemented`,
);
};
}
}
20 changes: 20 additions & 0 deletions src/strategies/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,24 @@ export namespace VerifyFunction {
req?: Request,
): Promise<IAuthUser | null>;
}

export interface KeycloakAuthFn {
(
accessToken: string,
refreshToken: string,
profile: KeycloakProfile,
cb: (err?: string | Error, user?: IAuthUser) => void,
): Promise<IAuthUser | null>;
}
}

export interface KeycloakProfile {
keycloakId: string;
fullName: string;
firstName: string;
lastName: string;
username: string;
email: string;
avatar: string;
realm: string;
}

0 comments on commit c2f91ad

Please sign in to comment.