Skip to content

Commit

Permalink
fix: express listener checks token auth for graph endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
ssube committed Dec 16, 2018
1 parent 6cae297 commit 17b03e7
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 26 deletions.
6 changes: 5 additions & 1 deletion docs/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 3 additions & 3 deletions docs/listener/express-listener.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
secret: test-secret
6 changes: 6 additions & 0 deletions docs/style.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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!
Expand Down
13 changes: 13 additions & 0 deletions src/graph/input/NameMultiValuePair.ts
Original file line number Diff line number Diff line change
@@ -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',
});
13 changes: 13 additions & 0 deletions src/graph/input/NameValuePair.ts
Original file line number Diff line number Diff line change
@@ -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',
});
41 changes: 29 additions & 12 deletions src/listener/ExpressListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export interface ExpressListenerOptions extends ChildServiceOptions<ExpressListe

@Inject('bot', 'metrics', 'services', 'storage')
export class ExpressListener extends SessionListener<ExpressListenerData> implements Listener {
protected readonly authenticator: passport.Authenticator;
protected readonly passport: passport.Authenticator;
protected readonly container: Container;
protected readonly metrics: Registry;
protected readonly requestCounter: Counter;
Expand All @@ -59,9 +59,9 @@ export class ExpressListener extends SessionListener<ExpressListenerData> 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;

Expand Down Expand Up @@ -110,7 +110,8 @@ export class ExpressListener extends SessionListener<ExpressListenerData> 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,
Expand All @@ -122,37 +123,53 @@ export class ExpressListener extends SessionListener<ExpressListenerData> 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<express.Express> {
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));
Expand All @@ -163,7 +180,7 @@ export class ExpressListener extends SessionListener<ExpressListenerData> implem
this.graph = await this.services.createService<GraphSchema, GraphSchemaData>(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,
}));
Expand Down
10 changes: 0 additions & 10 deletions src/schema.gql
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
input NameValuePairInput {
name: String!
value: String!
}

input NameMultiValuePairInput {
name: String!
values: [String!]!
}

input ChannelInput {
id: String!
thread: String
Expand Down

0 comments on commit 17b03e7

Please sign in to comment.