import { Router } from 'express' ; import session from 'express-session' ; import Keycloak from 'keycloak-connect' ; import { KeycloakTypeDefs , KeycloakSchemaDirectives , KeycloakContext , KeycloakSubscriptionHandler , KeycloakSubscriptionContext } from 'keycloak-connect-graphql' ; import { SecurityService , ApplyAuthMiddlewareOptions , KeycloakSecurityServiceOptions , AuthContextProviderClass , Logger } from './api' ; export class KeycloakSecurityService implements SecurityService { public readonly keycloakConfig : any ; public readonly schemaDirectives : any ; public readonly authContextProvider : any ; public keycloak : any ; public readonly log : Logger ; constructor ( keycloakConfig , options ? ) { this . keycloakConfig = keycloakConfig ; this . log = options && options . log ? options . log : console ; if ( options && options . keycloak ) { this . keycloak = options . keycloak ; } } public getTypeDefs ( ) { return KeycloakTypeDefs ; } public getSchemaDirectives ( ) { return KeycloakSchemaDirectives ; } public getAuthContextProvider ( ) { return KeycloakContext ; } param { * } expressRouter param { string } apiPath public applyAuthMiddleware ( expressRouter , options ? ) { if ( ! this . keycloakConfig ) { return this . log . info ( 'Keycloak authentication is not configured' ) ; } const apiPath = options && options . apiPath ? options . apiPath : '/graphql' ; const tokenEndpoint = options && options . tokenEndpoint ? options . tokenEndpoint : false ; this . log . info ( 'Initializing Keycloak authentication' ) ; const memoryStore = new session . MemoryStore ( ) ; expressRouter . use ( session ( { secret : this . keycloakConfig . secret || 'secret' , resave : false , saveUninitialized : true , store : memoryStore } ) as any ) ; if ( ! this . keycloak ) { this . keycloak = new Keycloak ( { store : memoryStore } , this . keycloakConfig ) ; } expressRouter . use ( this . keycloak . middleware ( { admin : apiPath } ) ) ; expressRouter . use ( apiPath , this . keycloak . protect ( ) ) ; if ( tokenEndpoint ) { expressRouter . get ( '/token' , this . keycloak . protect ( ) , function ( req , res ) { if ( req . session && req . session [ 'keycloak-token' ] ) { return res . json ( { 'Authorization' : 'Bearer ' + JSON . parse ( req . session [ 'keycloak-token' ] ) . access_token } ) ; } res . json ( { } ) ; } ) ; } } public async onSubscriptionConnect ( connectionParams , webSocket , context ) { const keycloakSubscriptionHandler = new KeycloakSubscriptionHandler ( { keycloak : this . keycloak } ) ; const token = await keycloakSubscriptionHandler . onSubscriptionConnect ( connectionParams , webSocket , context ) ; const subscriptionContext = new KeycloakSubscriptionContext ( token as any ) ; return { kauth : subscriptionContext , auth : subscriptionContext } ; } }