Token handling
file: code/Validad::Tools::Plack::Middleware::ExtractToken
1: package Validad::Tools::Plack::Middleware::ExtractToken;
2:
3: use strict;
4: use warnings;
5: use 5.010;
6:
7: use parent 'Plack::Middleware';
8:
9: use Plack::Util::Accessor qw(schema api_clients client_loader);
10: use HTTP::Throwable::Factory qw(http_throw);
11: use Validad::Tools::Functions::DecodeJWT qw(decode_jwt inspect_jwt);
12:
13: sub prepare_app {
14: my ($self) = @_;
15:
16: $self->api_clients( {} );
17: }
18:
19: sub call {
20: my $self = shift;
21: my $env = shift;
22:
23: if ( $self->found_bearer_token($env) ) {
24: return $self->app->($env);
25: }
26:
27: if ( $self->found_api_key($env) ) {
28: return $self->app->($env);
29: }
30:
31: return $self->app->($env);
32: }
33:
34: sub found_bearer_token {
35: my ( $self, $env ) = @_;
36:
37: my $auth_header = $env->{HTTP_AUTHORIZATION};
38: return unless $auth_header;
39: my ( $type, $token ) = split( /\s+/, $auth_header, 2 );
40:
41: if ( $type && lc($type) eq 'bearer' && $token ) {
42: my $unsave_claims = inspect_jwt($token);
43:
44: my $client = $self->get_client( $unsave_claims->{aud} );
45: my $claims = decode_jwt( $token, $client->{secret} );
46: $env->{'psgix.token.token'} = $token;
47: $env->{'psgix.token.claims'} = $claims;
48: $self->add_client_to_psgix( $env, $client );
49: return 1;
50: }
51: return 0;
52: }
53:
54: sub found_api_key {
55: my ( $self, $env ) = @_;
56:
57: my $path = $env->{PATH_INFO};
58: return 0
59: unless $path =~
60: m{^/api/v\d+/[[:xdigit:]]{8}-(?:[[:xdigit:]]{4}-){3}[[:xdigit:]]{12}/};
61:
62: my $key = $env->{'HTTP_X_API_KEY'};
63: if ( !$key ) {
64: $path =~ m{/api/v\d+/(.*?)/};
65: $key = $1;
66: }
67: if ($key) {
68: my $client = $self->get_client($key);
69: $self->add_client_to_psgix( $env, $client );
70: $env->{'psgix._api_key_in_url'} = 1;
71:
72: return 1;
73: }
74: }
75:
76: sub add_client_to_psgix {
77: my ( $self, $env, $client ) = @_;
78:
79: my $key = $env->{'psgix.api_key'} = $client->{key};
80: $env->{'psgix.api_id'} = $client->{id};
81: $env->{'psgix.api_name'} = $client->{name};
82:
83: $env->{PATH_INFO} =~ s{/$key}{};
84: }
85:
86: sub get_client {
87: my ( $self, $key ) = @_;
88:
89: my $cached = $self->api_clients->{$key};
90: return $cached if $cached;
91:
92: # removed code from example
93: if (my $client)
94: $self->api_clients->{$key} = $client;
95: return $client;
96: }
97: http_throw( BadRequest => { message => "Invalid api key >$key<" } );
98: }
99:
100: 1;