diff --git a/docs/auth.md b/docs/auth.md index 4d5588659..e2c69c04c 100644 --- a/docs/auth.md +++ b/docs/auth.md @@ -80,7 +80,11 @@ To create a new user and role with the reference config, please run: ### Login -TODO: how to log in +To log in with the reference config, please run: + +```none +!!login --name test_user +``` ### Session diff --git a/docs/listener/express-listener.yml b/docs/listener/express-listener.yml index b0a94363c..8746e041a 100644 --- a/docs/listener/express-listener.yml +++ b/docs/listener/express-listener.yml @@ -15,7 +15,7 @@ data: port: 4000 address: "0.0.0.0" token: - audience: [test] - issuer: test + audience: [test-audience] + issuer: test-issuer scheme: isolex - secret: test-secret-foo \ No newline at end of file + secret: test-secret \ No newline at end of file diff --git a/docs/style.md b/docs/style.md index db2fb1a95..e491bb8f6 100644 --- a/docs/style.md +++ b/docs/style.md @@ -6,6 +6,7 @@ This document covers Typescript and YAML style, explains some lint rules, and ma - [Code Climate](#code-climate) - [Close Reasons](#close-reasons) - [Noun/Verb Switch Complexity](#nounverb-switch-complexity) + - [Test Data & Fixtures](#test-data--fixtures) - [Documentation](#documentation) - [Headers](#headers) - [Table of Contents](#table-of-contents) @@ -48,6 +49,11 @@ Only the warnings shown here can be closed. Others must be fixed. Any complexity, duplication, or length warnings related to a controller's noun or verb switches should be marked as `WONTFIX`. +#### Test Data & Fixtures + +Any duplication or length warnings related to test data, especially object literals in constructors, and other fixtures +should be marked as `WONTFIX`. + ## Documentation Write it! diff --git a/src/graph/input/NameMultiValuePair.ts b/src/graph/input/NameMultiValuePair.ts new file mode 100644 index 000000000..aa0ac2537 --- /dev/null +++ b/src/graph/input/NameMultiValuePair.ts @@ -0,0 +1,13 @@ +import { GraphQLList, GraphQLObjectType, GraphQLString } from 'graphql'; + +export const GRAPH_INPUT_NAME_MULTI_VALUE_PAIR = new GraphQLObjectType({ + fields: { + name: { + type: GraphQLString, + }, + values: { + type: new GraphQLList(GraphQLString), + } + }, + name: 'NameMultiValuePairInput', +}); diff --git a/src/graph/input/NameValuePair.ts b/src/graph/input/NameValuePair.ts new file mode 100644 index 000000000..ecefa144d --- /dev/null +++ b/src/graph/input/NameValuePair.ts @@ -0,0 +1,13 @@ +import { GraphQLObjectType, GraphQLString } from 'graphql'; + +export const GRAPH_INPUT_NAME_VALUE_PAIR = new GraphQLObjectType({ + fields: { + name: { + type: GraphQLString, + }, + value: { + type: GraphQLString, + } + }, + name: 'NameValuePairInput', +}); diff --git a/src/listener/ExpressListener.ts b/src/listener/ExpressListener.ts index dd5df3657..6ce282f22 100644 --- a/src/listener/ExpressListener.ts +++ b/src/listener/ExpressListener.ts @@ -44,7 +44,7 @@ export interface ExpressListenerOptions extends ChildServiceOptions implements Listener { - protected readonly authenticator: passport.Authenticator; + protected readonly passport: passport.Authenticator; protected readonly container: Container; protected readonly metrics: Registry; protected readonly requestCounter: Counter; @@ -59,9 +59,9 @@ export class ExpressListener extends SessionListener implem constructor(options: ExpressListenerOptions) { super(options); - this.authenticator = new passport.Passport(); this.container = options.container; this.metrics = options.metrics; + this.passport = new passport.Passport(); this.services = options.services; this.storage = options.storage; @@ -110,7 +110,8 @@ export class ExpressListener extends SessionListener implem } public async traceRequest(req: express.Request, res: express.Response, next: Function) { - this.logger.debug({ req, res }, 'handling request'); + const ctx = req.user as Context | undefined; + this.logger.debug({ ctx, req, res }, 'handling request'); this.requestCounter.inc({ requestClient: req.ip, requestHost: req.hostname, @@ -122,37 +123,53 @@ export class ExpressListener extends SessionListener implem next(); } - protected async createTokenSession(req: express.Request, data: any, done: VerifiedCallback) { - this.logger.debug({ data, req }, 'finding token for request payload'); - const token = await this.tokenRepository.findOne(data); + protected async createTokenSession(data: any, done: VerifiedCallback) { + this.logger.debug({ data }, 'finding token for request payload'); + const token = await this.tokenRepository.findOne(data, { + relations: ['user'], + }); if (isNil(token)) { this.logger.warn('token not found'); return done(undefined, false); } + this.logger.debug({ token, user: token.user }, 'found token, creating context'); const ctx = new Context({ - ...data, + channel: { + id: '', + thread: '', + }, + name: token.user.name, source: this, + token, + uid: token.user.id, user: token.user, }); const session = token.session(this); - this.sessions.set(token.id, session); + this.sessions.set(token.user.id, session); this.logger.debug({ session }, 'created session for token'); + // tslint:disable-next-line:no-null-keyword done(null, ctx); } protected async setupApp(): Promise { - this.authenticator.use(new JwtStrategy({ + this.passport.use(new JwtStrategy({ audience: this.data.token.audience, issuer: this.data.token.issuer, jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme(this.data.token.scheme), secretOrKey: this.data.token.secret, - }, (req: express.Request, payload: any, done: VerifiedCallback) => this.createTokenSession(req, payload, done))); + }, (payload: any, done: VerifiedCallback) => this.createTokenSession(payload, done))); + this.passport.serializeUser((user: Context, done) => { + done(null, user.uid); + }); + this.passport.deserializeUser((user: Context, done) => { + done(null, this.sessions.get(user.uid)); + }); const app = express(); - app.use(this.authenticator.initialize()); + app.use(this.passport.initialize()); if (this.data.expose.metrics) { app.use((req, res, next) => this.traceRequest(req, res, next)); @@ -163,7 +180,7 @@ export class ExpressListener extends SessionListener implem this.graph = await this.services.createService(this.data.graph); await this.graph.start(); - app.use('/graph', expressGraphQl({ + app.use('/graph', this.passport.authenticate('jwt'), expressGraphQl({ graphiql: this.data.expose.graphiql, schema: this.graph.schema, })); diff --git a/src/schema.gql b/src/schema.gql index e0068fe19..48741e1d1 100644 --- a/src/schema.gql +++ b/src/schema.gql @@ -1,13 +1,3 @@ -input NameValuePairInput { - name: String! - value: String! -} - -input NameMultiValuePairInput { - name: String! - values: [String!]! -} - input ChannelInput { id: String! thread: String