Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
breaking: remove SecurityService interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Dara Hayes committed Jul 5, 2019
1 parent ea4bcd8 commit 6b82d5e
Show file tree
Hide file tree
Showing 17 changed files with 106 additions and 316 deletions.
128 changes: 0 additions & 128 deletions src/KeycloakSecurityService.ts

This file was deleted.

45 changes: 45 additions & 0 deletions src/KeycloakSubscriptionHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Token } from './KeycloakToken'
import { KeycloakSubscriptionHandlerOptions } from './api'

export class KeycloakSubscriptionHandler {

public readonly keycloakConfig: any
public readonly schemaDirectives: any
public readonly authContextProvider: any
public keycloak: any

constructor (options: KeycloakSubscriptionHandlerOptions) {
if (!options.keycloak) {
throw new Error('missing keycloak instance in options')
}
this.keycloak = options.keycloak
}

public async onSubscriptionConnect(connectionParams: any, webSocket: any, context: any): Promise<any> {
if (!connectionParams || typeof connectionParams !== 'object') {
throw new Error('Access Denied - missing connection parameters for Authentication')
}
const header = connectionParams.Authorization
|| connectionParams.authorization
|| connectionParams.Auth
|| connectionParams.auth
const clientId = connectionParams.clientId
if (!header) {
throw new Error('Access Denied - missing Authorization field in connection parameters')
}
const token = this.getBearerTokenFromHeader(header, clientId)
try {
await this.keycloak.grantManager.validateToken(token, 'Bearer')
return token
} catch (e) {
throw new Error(`Access Denied - ${e}`)
}
}

private getBearerTokenFromHeader(header: any, clientId?: string) {
if (header && typeof header === 'string' && (header.indexOf('bearer ') === 0 || header.indexOf('Bearer ') === 0)) {
const token = header.substring(7)
return new Token(token, clientId)
}
}
}
16 changes: 0 additions & 16 deletions src/api/ApplyAuthMiddlewareOptions.ts

This file was deleted.

35 changes: 0 additions & 35 deletions src/api/DefaultSecurityService.ts

This file was deleted.

9 changes: 0 additions & 9 deletions src/api/KeycloakSecurityServiceOptions.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/api/KeycloakSubscriptionHandlerOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface KeycloakSubscriptionHandlerOptions {
keycloak: any
}
61 changes: 0 additions & 61 deletions src/api/SecurityService.ts

This file was deleted.

6 changes: 1 addition & 5 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
export * from './SecurityService'
export * from './DefaultSecurityService'
export * from './AuthContextProvider'
export * from './SecurityService'
export * from './ApplyAuthMiddlewareOptions'
export * from './KeycloakSecurityServiceOptions'
export * from './KeycloakSubscriptionHandlerOptions'
export * from './SchemaDirectives'
24 changes: 24 additions & 0 deletions src/directives/directiveResolvers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export const auth = (next: Function) => (root: any, args: any, context: any, info: any) => {
if (!context.auth || !context.auth.isAuthenticated()) {
throw new Error(`User not Authenticated`)
}
return next(root, args, context, info)
}

export const hasRole = (roles: Array<string>) => (next: Function) => (root: any, args: any, context: any, info: any) => {
if (!context.auth || !context.auth.isAuthenticated()) {
throw new Error(`User not Authenticated`)
}

let foundRole = null // this will be the role the user was successfully authorized on

foundRole = roles.find((role: string) => {
return context.auth.hasRole(role)
})

if (!foundRole) {
throw new Error(`User is not authorized. Must have one of the following roles: [${roles}]`)
}

return next(root, args, context, info)
}
3 changes: 1 addition & 2 deletions src/schemaDirectives/index.ts → src/directives/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { HasRoleDirective } from './hasRole'
import { AuthDirective } from './auth'
import { HasRoleDirective, AuthDirective } from './schemaDirectiveVisitors'

export const schemaDirectives = {
auth: AuthDirective,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
import { defaultFieldResolver, GraphQLSchema } from 'graphql'
import { SchemaDirectiveVisitor } from 'graphql-tools'
import Joi from 'joi'
import { directiveResolvers } from './directiveResolvers'
import { auth, hasRole } from './directiveResolvers'
import { VisitableSchemaType } from 'graphql-tools/dist/schemaVisitor'

export class AuthDirective extends SchemaDirectiveVisitor {

constructor (config: {
name: string
visitedType: VisitableSchemaType
schema: GraphQLSchema
context: { [key: string]: any }
}) {
// see https://github.com/apollographql/graphql-tools/issues/837
super(config as any)
}

public visitFieldDefinition (field: any) {
const { resolve = defaultFieldResolver } = field
field.resolve = auth(resolve)
}
}

export class HasRoleDirective extends SchemaDirectiveVisitor {

constructor (config: {
Expand All @@ -26,7 +44,7 @@ export class HasRoleDirective extends SchemaDirectiveVisitor {

const { roles } = value

field.resolve = directiveResolvers.hasRole(roles)(resolve)
field.resolve = hasRole(roles)(resolve)
}

public validateArgs () {
Expand Down
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './KeycloakSecurityService'
export * from './KeycloakSubscriptionHandler'
export * from './AuthContextProvider'
export * from './directives'
export * from './api'

0 comments on commit 6b82d5e

Please sign in to comment.