mirror of
https://github.com/valitydev/openapi-generator.git
synced 2024-11-08 11:23:58 +00:00
Handle missing security spec more elegantly
- remove the optional auth_setup_handler() callback mechanism - add _global_auth_setup() method on ApiClient to analyse config when security spec not provided - add methods on the Configuration class to abstract getting and setting tokens
This commit is contained in:
parent
06db67210c
commit
2144cf5d31
@ -34,6 +34,8 @@ sub _new_instance
|
||||
return bless \%args, $class;
|
||||
}
|
||||
|
||||
sub _cfg {'WWW::{{moduleName}}::Configuration'}
|
||||
|
||||
# Set the user agent of the API client
|
||||
#
|
||||
# @param string $user_agent The user agent of the API client
|
||||
@ -308,18 +310,8 @@ sub get_api_key_with_prefix
|
||||
sub update_params_for_auth {
|
||||
my ($self, $header_params, $query_params, $auth_settings) = @_;
|
||||
|
||||
# we can defer to the application if the spec doesn't describe authentication
|
||||
if ($self->{auth_setup_handler_object}) {
|
||||
$self->{auth_setup_handler_object}->auth_setup_handler(
|
||||
api_client => $self,
|
||||
header_params => $header_params,
|
||||
query_params => $query_params,
|
||||
auth_settings => $auth_settings, # presumably this won't be defined if we're doing it this way
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
return if (!defined($auth_settings) || scalar(@$auth_settings) == 0);
|
||||
return $self->_global_auth_setup($header_params, $query_params)
|
||||
unless $auth_settings && @$auth_settings;
|
||||
|
||||
# one endpoint can have more than 1 auth settings
|
||||
foreach my $auth (@$auth_settings) {
|
||||
@ -332,10 +324,47 @@ sub update_params_for_auth {
|
||||
}
|
||||
{{/authMethods}}
|
||||
else {
|
||||
# TODO show warning about security definition not found
|
||||
# TODO show warning about security definition not found
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# The endpoint API class has not found any settings for auth. This may be deliberate,
|
||||
# in which case update_params_for_auth() will be a no-op. But it may also be that the
|
||||
# swagger spec does not describe the intended authorization. So we check in the config for any
|
||||
# auth tokens and if we find any, we use them for all endpoints;
|
||||
sub _global_auth_setup {
|
||||
my ($self, $header_params, $query_params) = @_;
|
||||
|
||||
my $tokens = $self->_cfg->get_tokens;
|
||||
return unless keys %$tokens;
|
||||
|
||||
# basic
|
||||
if (my $uname = delete $tokens->{username}) {
|
||||
my $pword = delete $tokens->{password};
|
||||
$header_params->{'Authorization'} = 'Basic '.encode_base64($uname.":".$pword);
|
||||
}
|
||||
|
||||
# oauth
|
||||
if (my $access_token = delete $tokens->{access_token}) {
|
||||
$header_params->{'Authorization'} = 'Bearer ' . $access_token;
|
||||
}
|
||||
|
||||
# other keys
|
||||
foreach my $token_name (keys %$tokens) {
|
||||
my $in = $tokens->{$token_name}->{in};
|
||||
my $token = $self->get_api_key_with_prefix($token_name);
|
||||
if ($in eq 'head') {
|
||||
$header_params->{$token_name} = $token;
|
||||
}
|
||||
elsif ($in eq 'query') {
|
||||
$query_params->{$token_name} = $token;
|
||||
}
|
||||
else {
|
||||
die "Don't know where to put token '$token_name' ('$in' is not 'head' or 'query')";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
@ -16,6 +16,7 @@ our $http_user_agent = 'Perl-Swagger';
|
||||
# authenticaiton setting
|
||||
our $api_key = {};
|
||||
our $api_key_prefix = {};
|
||||
our $api_key_in = {};
|
||||
|
||||
# username and password for HTTP basic authentication
|
||||
our $username = '';
|
||||
@ -24,4 +25,56 @@ our $password = '';
|
||||
# access token for OAuth
|
||||
our $access_token = '';
|
||||
|
||||
sub get_tokens {
|
||||
my $class = shift;
|
||||
|
||||
my $tokens = {};
|
||||
$tokens->{username} = $username if $username;
|
||||
$tokens->{password} = $password if $password;
|
||||
$tokens->{access_token} = $access_token if $access_token;
|
||||
|
||||
foreach my $token_name (keys %{ $api_key }) {
|
||||
$tokens->{$token_name}->{token} = $api_key->{$token_name};
|
||||
$tokens->{$token_name}->{prefix} = $api_key_prefix->{$token_name};
|
||||
$tokens->{$token_name}->{in} = $api_key_in->{$token_name};
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
sub clear_tokens {
|
||||
my $class = shift;
|
||||
my %tokens = %{$class->get_tokens}; # copy
|
||||
|
||||
$username = undef;
|
||||
$password = undef;
|
||||
$access_token = undef;
|
||||
|
||||
$api_key = {};
|
||||
$api_key_prefix = {};
|
||||
$api_key_in = {};
|
||||
|
||||
return \%tokens;
|
||||
}
|
||||
|
||||
sub accept_tokens {
|
||||
my ($class, $tokens) = @_;
|
||||
|
||||
foreach my $known_name (qw(username password access_token)) {
|
||||
next unless $tokens->{$known_name};
|
||||
eval "\$$known_name = delete \$tokens->{\$known_name}";
|
||||
die $@ if $@;
|
||||
}
|
||||
|
||||
foreach my $token_name (keys %$tokens) {
|
||||
$api_key->{$token_name} = $tokens->{$token_name}->{token};
|
||||
if ($tokens->{$token_name}->{prefix}) {
|
||||
$api_key_prefix->{$token_name} = $tokens->{$token_name}->{prefix};
|
||||
}
|
||||
my $in = $tokens->{$token_name}->{in} || 'head';
|
||||
croak "Tokens can only go in 'head' or 'query' (not in '$in')" unless $in =~ /^(?:head|query)$/;
|
||||
$api_key_in->{$token_name} = $in;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -23,7 +23,7 @@ role.
|
||||
|
||||
package main;
|
||||
|
||||
my $api = MyApp->new;
|
||||
my $api = MyApp->new({ tokens => $tokens });
|
||||
|
||||
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
|
||||
|
||||
@ -46,14 +46,40 @@ For documentation of all these methods, see AUTOMATIC DOCUMENTATION below.
|
||||
|
||||
## Configuring authentication
|
||||
|
||||
If your Swagger spec does not describe authentication, you can write an
|
||||
`auth_setup_handler()` method in your base class to handle it (see below).
|
||||
In the normal case, the Swagger spec will describe what parameters are
|
||||
required and where to put them. You just need to supply the tokens.
|
||||
|
||||
In the normal case, the Swagger spec will describe what parameters are required
|
||||
and where to put them. You just need to supply the authorization tokens.
|
||||
my $tokens = {
|
||||
# basic
|
||||
username => $username,
|
||||
password => $password,
|
||||
|
||||
# oauth
|
||||
access_token => $oauth_token,
|
||||
|
||||
# keys
|
||||
$some_key => { token => $token,
|
||||
prefix => $prefix,
|
||||
in => $in, # 'head||query',
|
||||
},
|
||||
|
||||
$another => { token => $token,
|
||||
prefix => $prefix,
|
||||
in => $in, # 'head||query',
|
||||
},
|
||||
...,
|
||||
|
||||
};
|
||||
|
||||
my $api = MyApp->new({ tokens => $tokens });
|
||||
|
||||
These should go in the `WWW::{{moduleName}}::Configuration` namespace as follows.
|
||||
Note these are all optional, and depend on the API you are accessing.
|
||||
Note these are all optional, as are `prefix` and `in`, and depend on the API
|
||||
you are accessing. Usually `prefix` and `in` will be determined by the code generator from
|
||||
the spec and you will not need to set them at run time. If not, `in` will
|
||||
default to 'head' and `prefix` to the empty string.
|
||||
|
||||
The tokens will be placed in the `WWW::{{moduleName}}::Configuration` namespace
|
||||
as follows, but you don't need to know about this.
|
||||
|
||||
- `$WWW::{{moduleName}}::Configuration::username`
|
||||
|
||||
@ -88,63 +114,19 @@ Note these are all optional, and depend on the API you are accessing.
|
||||
|
||||
# METHODS
|
||||
|
||||
## `auth_setup_handler()`
|
||||
|
||||
This method does not exist! But if you add it to the class that consumes this
|
||||
role, it will be called to set up authentication.
|
||||
|
||||
package MyApp;
|
||||
use Moose;
|
||||
|
||||
with 'WWW::{{moduleName}}::Role';
|
||||
|
||||
sub auth_setup_handler {
|
||||
my ($self, %p) = @_;
|
||||
$p{header_params}->{'X-TargetApp-apiKey'} = $api_key;
|
||||
$p{header_params}->{'X-TargetApp-secretKey'} = $secret_key;
|
||||
}
|
||||
|
||||
# somewhere else...
|
||||
|
||||
my $api = MyApp->new;
|
||||
|
||||
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
|
||||
|
||||
So, `auth_setup_handler()` will be called on your `$api` object and passed the
|
||||
following parameters:
|
||||
|
||||
- `header_params`
|
||||
|
||||
A hashref that will become the request headers. You can insert auth
|
||||
parameters.
|
||||
|
||||
- `query_params`
|
||||
|
||||
A hashref that will be encoded into the request URL. You can insert auth
|
||||
parameters.
|
||||
|
||||
- `auth_settings`
|
||||
|
||||
TODO. Probably not necessary?
|
||||
|
||||
- `api_client`
|
||||
|
||||
A reference to the `WWW::{{moduleName}}::ApiClient` object that is responsible
|
||||
for communicating with the server. Just in case that's useful.
|
||||
|
||||
## base\_url
|
||||
## `base_url`
|
||||
|
||||
The generated code has the `base_url` already set as a default value. This method
|
||||
returns (and optionally sets, but only if the API client has not been
|
||||
created yet) the current value of `base_url`.
|
||||
|
||||
## api\_factory
|
||||
## `api_factory`
|
||||
|
||||
Returns an API factory object. You probably won't need to call this directly.
|
||||
|
||||
$self->api_factory('Pet'); # returns a WWW::{{moduleName}}::PetApi instance
|
||||
|
||||
$self->pet_api; # the same
|
||||
$self->pet_api; # the same
|
||||
|
||||
# MISSING METHODS
|
||||
|
||||
@ -202,11 +184,11 @@ Additional documentation for each class and method may be provided by the Swagge
|
||||
spec. If so, this is available via the `class_documentation()` and
|
||||
`method_documentation()` methods on each generated API and class:
|
||||
|
||||
my $cdoc = $api->pet_api->class_documentation;
|
||||
my $cdoc = $api->pet_api->class_documentation;
|
||||
my $cmdoc = $api->pet_api->method_documentation->{$method_name};
|
||||
|
||||
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation;
|
||||
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation;
|
||||
my $omdoc = $api->get_pet_by_id->(pet_id => $pet_id)->method_documentation->{method_name};
|
||||
|
||||
|
||||
Each of these calls returns a hashref with various useful pieces of information.
|
||||
Each of these calls returns a hashref with various useful pieces of information.
|
||||
|
@ -8,19 +8,32 @@ use Log::Any qw($log);
|
||||
use WWW::{{moduleName}}::ApiFactory;
|
||||
|
||||
has base_url => ( is => 'ro',
|
||||
required => 0,
|
||||
isa => 'Str',
|
||||
);
|
||||
required => 0,
|
||||
isa => 'Str',
|
||||
);
|
||||
|
||||
has api_factory => ( is => 'ro',
|
||||
isa => 'WWW::{{moduleName}}::ApiFactory',
|
||||
builder => '_build_af',
|
||||
lazy => 1,
|
||||
);
|
||||
|
||||
has tokens => ( is => 'ro',
|
||||
isa => 'HashRef',
|
||||
required => 0,
|
||||
default => sub {{=<% %>=}}{{}}<%={{ }}=%>, # !
|
||||
);
|
||||
|
||||
has _cfg => ( is => 'ro',
|
||||
isa => 'Str',
|
||||
default => 'WWW::{{moduleName}}::Configuration',
|
||||
);
|
||||
|
||||
sub BUILD {
|
||||
my $self = shift;
|
||||
|
||||
$self->_cfg->accept_tokens( $self->tokens ) if keys %{$self->tokens};
|
||||
|
||||
# ignore these symbols imported into API namespaces
|
||||
my %outsiders = map {$_ => 1} qw( croak );
|
||||
|
||||
@ -93,7 +106,7 @@ role.
|
||||
|
||||
package main;
|
||||
|
||||
my $api = MyApp->new;
|
||||
my $api = MyApp->new({ tokens => $tokens });
|
||||
|
||||
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
|
||||
|
||||
@ -115,14 +128,40 @@ For documentation of all these methods, see AUTOMATIC DOCUMENTATION below.
|
||||
|
||||
=head2 Configuring authentication
|
||||
|
||||
If your Swagger spec does not describe authentication, you can write an
|
||||
C<auth_setup_handler()> method in your base class to handle it (see below).
|
||||
In the normal case, the Swagger spec will describe what parameters are
|
||||
required and where to put them. You just need to supply the tokens.
|
||||
|
||||
In the normal case, the Swagger spec will describe what parameters are required
|
||||
and where to put them. You just need to supply the authorization tokens.
|
||||
my $tokens = {
|
||||
# basic
|
||||
username => $username,
|
||||
password => $password,
|
||||
|
||||
# oauth
|
||||
access_token => $oauth_token,
|
||||
|
||||
# keys
|
||||
$some_key => { token => $token,
|
||||
prefix => $prefix,
|
||||
in => $in, # 'head||query',
|
||||
},
|
||||
|
||||
$another => { token => $token,
|
||||
prefix => $prefix,
|
||||
in => $in, # 'head||query',
|
||||
},
|
||||
...,
|
||||
|
||||
};
|
||||
|
||||
my $api = MyApp->new({ tokens => $tokens });
|
||||
|
||||
These should go in the C<WWW::{{moduleName}}::Configuration> namespace as follows.
|
||||
Note these are all optional, and depend on the API you are accessing.
|
||||
Note these are all optional, as are C<prefix> and C<in>, and depend on the API
|
||||
you are accessing. Usually C<prefix> and C<in> will be determined by the code generator from
|
||||
the spec and you will not need to set them at run time. If not, C<in> will
|
||||
default to 'head' and C<prefix> to the empty string.
|
||||
|
||||
The tokens will be placed in the C<WWW::{{moduleName}}::Configuration> namespace
|
||||
as follows, but you don't need to know about this.
|
||||
|
||||
=over 4
|
||||
|
||||
@ -161,68 +200,19 @@ String. The OAuth access token.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 C<auth_setup_handler()>
|
||||
|
||||
This method does not exist! But if you add it to the class that consumes this
|
||||
role, it will be called to set up authentication.
|
||||
|
||||
package MyApp;
|
||||
use Moose;
|
||||
|
||||
with 'WWW::{{moduleName}}::Role';
|
||||
|
||||
sub auth_setup_handler {
|
||||
my ($self, %p) = @_;
|
||||
$p{header_params}->{'X-TargetApp-apiKey'} = $api_key;
|
||||
$p{header_params}->{'X-TargetApp-secretKey'} = $secret_key;
|
||||
}
|
||||
|
||||
# somewhere else...
|
||||
|
||||
my $api = MyApp->new;
|
||||
|
||||
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
|
||||
|
||||
|
||||
So, C<auth_setup_handler()> will be called on your C<$api> object and passed the
|
||||
following parameters:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<header_params>
|
||||
|
||||
A hashref that will become the request headers. You can insert auth
|
||||
parameters.
|
||||
|
||||
=item C<query_params>
|
||||
|
||||
A hashref that will be encoded into the request URL. You can insert auth
|
||||
parameters.
|
||||
|
||||
=item C<auth_settings>
|
||||
|
||||
TODO. Probably not necessary?
|
||||
|
||||
=item C<api_client>
|
||||
|
||||
A reference to the C<WWW::{{moduleName}}::ApiClient> object that is responsible
|
||||
for communicating with the server. Just in case that's useful.
|
||||
|
||||
=back
|
||||
|
||||
=head2 base_url
|
||||
=head2 C<base_url>
|
||||
|
||||
The generated code has the C<base_url> already set as a default value. This method
|
||||
returns (and optionally sets, but only if the API client has not been
|
||||
created yet) the current value of C<base_url>.
|
||||
|
||||
=head2 api_factory
|
||||
=head2 C<api_factory>
|
||||
|
||||
Returns an API factory object. You probably won't need to call this directly.
|
||||
|
||||
$self->api_factory('Pet'); # returns a WWW::{{moduleName}}::PetApi instance
|
||||
|
||||
$self->pet_api; # the same
|
||||
$self->pet_api; # the same
|
||||
|
||||
=head1 MISSING METHODS
|
||||
|
||||
@ -280,13 +270,13 @@ Additional documentation for each class and method may be provided by the Swagge
|
||||
spec. If so, this is available via the C<class_documentation()> and
|
||||
C<method_documentation()> methods on each generated API and class:
|
||||
|
||||
my $cdoc = $api->pet_api->class_documentation;
|
||||
my $cdoc = $api->pet_api->class_documentation;
|
||||
my $cmdoc = $api->pet_api->method_documentation->{$method_name};
|
||||
|
||||
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation;
|
||||
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation;
|
||||
my $omdoc = $api->get_pet_by_id->(pet_id => $pet_id)->method_documentation->{method_name};
|
||||
|
||||
Each of these calls returns a hashref with various useful pieces of information.
|
||||
Each of these calls returns a hashref with various useful pieces of information.
|
||||
|
||||
=cut
|
||||
|
||||
|
@ -134,7 +134,7 @@ sub {{nickname}} {
|
||||
}{{/bodyParams}}
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [{{#authMethods}}'{{name}}'{{#hasMore}}, {{/hasMore}}{{/authMethods}}];
|
||||
my $auth_settings = [qw({{#authMethods}}{{name}} {{/authMethods}})];
|
||||
|
||||
# make the API Call
|
||||
{{#returnType}}my $response = $self->{api_client}->call_api($_resource_path, $_method,
|
||||
|
@ -23,7 +23,7 @@ role.
|
||||
|
||||
package main;
|
||||
|
||||
my $api = MyApp->new;
|
||||
my $api = MyApp->new({ tokens => $tokens });
|
||||
|
||||
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
|
||||
|
||||
@ -46,14 +46,40 @@ For documentation of all these methods, see AUTOMATIC DOCUMENTATION below.
|
||||
|
||||
## Configuring authentication
|
||||
|
||||
If your Swagger spec does not describe authentication, you can write an
|
||||
`auth_setup_handler()` method in your base class to handle it (see below).
|
||||
In the normal case, the Swagger spec will describe what parameters are
|
||||
required and where to put them. You just need to supply the tokens.
|
||||
|
||||
In the normal case, the Swagger spec will describe what parameters are required
|
||||
and where to put them. You just need to supply the authorization tokens.
|
||||
my $tokens = {
|
||||
# basic
|
||||
username => $username,
|
||||
password => $password,
|
||||
|
||||
# oauth
|
||||
access_token => $oauth_token,
|
||||
|
||||
# keys
|
||||
$some_key => { token => $token,
|
||||
prefix => $prefix,
|
||||
in => $in, # 'head||query',
|
||||
},
|
||||
|
||||
$another => { token => $token,
|
||||
prefix => $prefix,
|
||||
in => $in, # 'head||query',
|
||||
},
|
||||
...,
|
||||
|
||||
};
|
||||
|
||||
my $api = MyApp->new({ tokens => $tokens });
|
||||
|
||||
These should go in the `WWW::SwaggerClient::Configuration` namespace as follows.
|
||||
Note these are all optional, and depend on the API you are accessing.
|
||||
Note these are all optional, as are `prefix` and `in`, and depend on the API
|
||||
you are accessing. Usually `prefix` and `in` will be determined by the code generator from
|
||||
the spec and you will not need to set them at run time. If not, `in` will
|
||||
default to 'head' and `prefix` to the empty string.
|
||||
|
||||
The tokens will be placed in the `WWW::SwaggerClient::Configuration` namespace
|
||||
as follows, but you don't need to know about this.
|
||||
|
||||
- `$WWW::SwaggerClient::Configuration::username`
|
||||
|
||||
@ -88,63 +114,19 @@ Note these are all optional, and depend on the API you are accessing.
|
||||
|
||||
# METHODS
|
||||
|
||||
## `auth_setup_handler()`
|
||||
|
||||
This method does not exist! But if you add it to the class that consumes this
|
||||
role, it will be called to set up authentication.
|
||||
|
||||
package MyApp;
|
||||
use Moose;
|
||||
|
||||
with 'WWW::SwaggerClient::Role';
|
||||
|
||||
sub auth_setup_handler {
|
||||
my ($self, %p) = @_;
|
||||
$p{header_params}->{'X-TargetApp-apiKey'} = $api_key;
|
||||
$p{header_params}->{'X-TargetApp-secretKey'} = $secret_key;
|
||||
}
|
||||
|
||||
# somewhere else...
|
||||
|
||||
my $api = MyApp->new;
|
||||
|
||||
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
|
||||
|
||||
So, `auth_setup_handler()` will be called on your `$api` object and passed the
|
||||
following parameters:
|
||||
|
||||
- `header_params`
|
||||
|
||||
A hashref that will become the request headers. You can insert auth
|
||||
parameters.
|
||||
|
||||
- `query_params`
|
||||
|
||||
A hashref that will be encoded into the request URL. You can insert auth
|
||||
parameters.
|
||||
|
||||
- `auth_settings`
|
||||
|
||||
TODO. Probably not necessary?
|
||||
|
||||
- `api_client`
|
||||
|
||||
A reference to the `WWW::SwaggerClient::ApiClient` object that is responsible
|
||||
for communicating with the server. Just in case that's useful.
|
||||
|
||||
## base\_url
|
||||
## `base_url`
|
||||
|
||||
The generated code has the `base_url` already set as a default value. This method
|
||||
returns (and optionally sets, but only if the API client has not been
|
||||
created yet) the current value of `base_url`.
|
||||
|
||||
## api\_factory
|
||||
## `api_factory`
|
||||
|
||||
Returns an API factory object. You probably won't need to call this directly.
|
||||
|
||||
$self->api_factory('Pet'); # returns a WWW::SwaggerClient::PetApi instance
|
||||
|
||||
$self->pet_api; # the same
|
||||
$self->pet_api; # the same
|
||||
|
||||
# MISSING METHODS
|
||||
|
||||
@ -202,11 +184,11 @@ Additional documentation for each class and method may be provided by the Swagge
|
||||
spec. If so, this is available via the `class_documentation()` and
|
||||
`method_documentation()` methods on each generated API and class:
|
||||
|
||||
my $cdoc = $api->pet_api->class_documentation;
|
||||
my $cdoc = $api->pet_api->class_documentation;
|
||||
my $cmdoc = $api->pet_api->method_documentation->{$method_name};
|
||||
|
||||
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation;
|
||||
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation;
|
||||
my $omdoc = $api->get_pet_by_id->(pet_id => $pet_id)->method_documentation->{method_name};
|
||||
|
||||
|
||||
Each of these calls returns a hashref with various useful pieces of information.
|
||||
Each of these calls returns a hashref with various useful pieces of information.
|
||||
|
@ -34,6 +34,8 @@ sub _new_instance
|
||||
return bless \%args, $class;
|
||||
}
|
||||
|
||||
sub _cfg {'WWW::SwaggerClient::Configuration'}
|
||||
|
||||
# Set the user agent of the API client
|
||||
#
|
||||
# @param string $user_agent The user agent of the API client
|
||||
@ -308,18 +310,8 @@ sub get_api_key_with_prefix
|
||||
sub update_params_for_auth {
|
||||
my ($self, $header_params, $query_params, $auth_settings) = @_;
|
||||
|
||||
# we can defer to the application if the spec doesn't describe authentication
|
||||
if ($self->{auth_setup_handler_object}) {
|
||||
$self->{auth_setup_handler_object}->auth_setup_handler(
|
||||
api_client => $self,
|
||||
header_params => $header_params,
|
||||
query_params => $query_params,
|
||||
auth_settings => $auth_settings, # presumably this won't be defined if we're doing it this way
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
return if (!defined($auth_settings) || scalar(@$auth_settings) == 0);
|
||||
return $self->_global_auth_setup($header_params, $query_params)
|
||||
unless $auth_settings && @$auth_settings;
|
||||
|
||||
# one endpoint can have more than 1 auth settings
|
||||
foreach my $auth (@$auth_settings) {
|
||||
@ -336,10 +328,47 @@ sub update_params_for_auth {
|
||||
}
|
||||
|
||||
else {
|
||||
# TODO show warning about security definition not found
|
||||
# TODO show warning about security definition not found
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# The endpoint API class has not found any settings for auth. This may be deliberate,
|
||||
# in which case update_params_for_auth() will be a no-op. But it may also be that the
|
||||
# swagger spec does not describe the intended authorization. So we check in the config for any
|
||||
# auth tokens and if we find any, we use them for all endpoints;
|
||||
sub _global_auth_setup {
|
||||
my ($self, $header_params, $query_params) = @_;
|
||||
|
||||
my $tokens = $self->_cfg->get_tokens;
|
||||
return unless keys %$tokens;
|
||||
|
||||
# basic
|
||||
if (my $uname = delete $tokens->{username}) {
|
||||
my $pword = delete $tokens->{password};
|
||||
$header_params->{'Authorization'} = 'Basic '.encode_base64($uname.":".$pword);
|
||||
}
|
||||
|
||||
# oauth
|
||||
if (my $access_token = delete $tokens->{access_token}) {
|
||||
$header_params->{'Authorization'} = 'Bearer ' . $access_token;
|
||||
}
|
||||
|
||||
# other keys
|
||||
foreach my $token_name (keys %$tokens) {
|
||||
my $in = $tokens->{$token_name}->{in};
|
||||
my $token = $self->get_api_key_with_prefix($token_name);
|
||||
if ($in eq 'head') {
|
||||
$header_params->{$token_name} = $token;
|
||||
}
|
||||
elsif ($in eq 'query') {
|
||||
$query_params->{$token_name} = $token;
|
||||
}
|
||||
else {
|
||||
die "Don't know where to put token '$token_name' ('$in' is not 'head' or 'query')";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
@ -16,6 +16,7 @@ our $http_user_agent = 'Perl-Swagger';
|
||||
# authenticaiton setting
|
||||
our $api_key = {};
|
||||
our $api_key_prefix = {};
|
||||
our $api_key_in = {};
|
||||
|
||||
# username and password for HTTP basic authentication
|
||||
our $username = '';
|
||||
@ -24,4 +25,56 @@ our $password = '';
|
||||
# access token for OAuth
|
||||
our $access_token = '';
|
||||
|
||||
sub get_tokens {
|
||||
my $class = shift;
|
||||
|
||||
my $tokens = {};
|
||||
$tokens->{username} = $username if $username;
|
||||
$tokens->{password} = $password if $password;
|
||||
$tokens->{access_token} = $access_token if $access_token;
|
||||
|
||||
foreach my $token_name (keys %{ $api_key }) {
|
||||
$tokens->{$token_name}->{token} = $api_key->{$token_name};
|
||||
$tokens->{$token_name}->{prefix} = $api_key_prefix->{$token_name};
|
||||
$tokens->{$token_name}->{in} = $api_key_in->{$token_name};
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
sub clear_tokens {
|
||||
my $class = shift;
|
||||
my %tokens = %{$class->get_tokens}; # copy
|
||||
|
||||
$username = undef;
|
||||
$password = undef;
|
||||
$access_token = undef;
|
||||
|
||||
$api_key = {};
|
||||
$api_key_prefix = {};
|
||||
$api_key_in = {};
|
||||
|
||||
return \%tokens;
|
||||
}
|
||||
|
||||
sub accept_tokens {
|
||||
my ($class, $tokens) = @_;
|
||||
|
||||
foreach my $known_name (qw(username password access_token)) {
|
||||
next unless $tokens->{$known_name};
|
||||
eval "\$$known_name = delete \$tokens->{\$known_name}";
|
||||
die $@ if $@;
|
||||
}
|
||||
|
||||
foreach my $token_name (keys %$tokens) {
|
||||
$api_key->{$token_name} = $tokens->{$token_name}->{token};
|
||||
if ($tokens->{$token_name}->{prefix}) {
|
||||
$api_key_prefix->{$token_name} = $tokens->{$token_name}->{prefix};
|
||||
}
|
||||
my $in = $tokens->{$token_name}->{in} || 'head';
|
||||
croak "Tokens can only go in 'head' or 'query' (not in '$in')" unless $in =~ /^(?:head|query)$/;
|
||||
$api_key_in->{$token_name} = $in;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -106,7 +106,7 @@ sub update_pet {
|
||||
}
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = ['petstore_auth'];
|
||||
my $auth_settings = [qw(petstore_auth )];
|
||||
|
||||
# make the API Call
|
||||
|
||||
@ -170,7 +170,7 @@ sub add_pet {
|
||||
}
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = ['petstore_auth'];
|
||||
my $auth_settings = [qw(petstore_auth )];
|
||||
|
||||
# make the API Call
|
||||
|
||||
@ -234,7 +234,7 @@ sub find_pets_by_status {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = ['petstore_auth'];
|
||||
my $auth_settings = [qw(petstore_auth )];
|
||||
|
||||
# make the API Call
|
||||
my $response = $self->{api_client}->call_api($_resource_path, $_method,
|
||||
@ -301,7 +301,7 @@ sub find_pets_by_tags {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = ['petstore_auth'];
|
||||
my $auth_settings = [qw(petstore_auth )];
|
||||
|
||||
# make the API Call
|
||||
my $response = $self->{api_client}->call_api($_resource_path, $_method,
|
||||
@ -375,7 +375,7 @@ sub get_pet_by_id {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = ['api_key'];
|
||||
my $auth_settings = [qw(api_key )];
|
||||
|
||||
# make the API Call
|
||||
my $response = $self->{api_client}->call_api($_resource_path, $_method,
|
||||
@ -471,7 +471,7 @@ sub update_pet_with_form {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = ['petstore_auth'];
|
||||
my $auth_settings = [qw(petstore_auth )];
|
||||
|
||||
# make the API Call
|
||||
|
||||
@ -551,7 +551,7 @@ sub delete_pet {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = ['petstore_auth'];
|
||||
my $auth_settings = [qw(petstore_auth )];
|
||||
|
||||
# make the API Call
|
||||
|
||||
@ -645,7 +645,7 @@ sub upload_file {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = ['petstore_auth'];
|
||||
my $auth_settings = [qw(petstore_auth )];
|
||||
|
||||
# make the API Call
|
||||
|
||||
|
@ -8,19 +8,32 @@ use Log::Any qw($log);
|
||||
use WWW::SwaggerClient::ApiFactory;
|
||||
|
||||
has base_url => ( is => 'ro',
|
||||
required => 0,
|
||||
isa => 'Str',
|
||||
);
|
||||
required => 0,
|
||||
isa => 'Str',
|
||||
);
|
||||
|
||||
has api_factory => ( is => 'ro',
|
||||
isa => 'WWW::SwaggerClient::ApiFactory',
|
||||
builder => '_build_af',
|
||||
lazy => 1,
|
||||
);
|
||||
|
||||
has tokens => ( is => 'ro',
|
||||
isa => 'HashRef',
|
||||
required => 0,
|
||||
default => sub {{}}, # !
|
||||
);
|
||||
|
||||
has _cfg => ( is => 'ro',
|
||||
isa => 'Str',
|
||||
default => 'WWW::SwaggerClient::Configuration',
|
||||
);
|
||||
|
||||
sub BUILD {
|
||||
my $self = shift;
|
||||
|
||||
$self->_cfg->accept_tokens( $self->tokens ) if keys %{$self->tokens};
|
||||
|
||||
# ignore these symbols imported into API namespaces
|
||||
my %outsiders = map {$_ => 1} qw( croak );
|
||||
|
||||
@ -93,7 +106,7 @@ role.
|
||||
|
||||
package main;
|
||||
|
||||
my $api = MyApp->new;
|
||||
my $api = MyApp->new({ tokens => $tokens });
|
||||
|
||||
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
|
||||
|
||||
@ -115,14 +128,40 @@ For documentation of all these methods, see AUTOMATIC DOCUMENTATION below.
|
||||
|
||||
=head2 Configuring authentication
|
||||
|
||||
If your Swagger spec does not describe authentication, you can write an
|
||||
C<auth_setup_handler()> method in your base class to handle it (see below).
|
||||
In the normal case, the Swagger spec will describe what parameters are
|
||||
required and where to put them. You just need to supply the tokens.
|
||||
|
||||
In the normal case, the Swagger spec will describe what parameters are required
|
||||
and where to put them. You just need to supply the authorization tokens.
|
||||
my $tokens = {
|
||||
# basic
|
||||
username => $username,
|
||||
password => $password,
|
||||
|
||||
# oauth
|
||||
access_token => $oauth_token,
|
||||
|
||||
# keys
|
||||
$some_key => { token => $token,
|
||||
prefix => $prefix,
|
||||
in => $in, # 'head||query',
|
||||
},
|
||||
|
||||
$another => { token => $token,
|
||||
prefix => $prefix,
|
||||
in => $in, # 'head||query',
|
||||
},
|
||||
...,
|
||||
|
||||
};
|
||||
|
||||
my $api = MyApp->new({ tokens => $tokens });
|
||||
|
||||
These should go in the C<WWW::SwaggerClient::Configuration> namespace as follows.
|
||||
Note these are all optional, and depend on the API you are accessing.
|
||||
Note these are all optional, as are C<prefix> and C<in>, and depend on the API
|
||||
you are accessing. Usually C<prefix> and C<in> will be determined by the code generator from
|
||||
the spec and you will not need to set them at run time. If not, C<in> will
|
||||
default to 'head' and C<prefix> to the empty string.
|
||||
|
||||
The tokens will be placed in the C<WWW::SwaggerClient::Configuration> namespace
|
||||
as follows, but you don't need to know about this.
|
||||
|
||||
=over 4
|
||||
|
||||
@ -161,68 +200,19 @@ String. The OAuth access token.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 C<auth_setup_handler()>
|
||||
|
||||
This method does not exist! But if you add it to the class that consumes this
|
||||
role, it will be called to set up authentication.
|
||||
|
||||
package MyApp;
|
||||
use Moose;
|
||||
|
||||
with 'WWW::SwaggerClient::Role';
|
||||
|
||||
sub auth_setup_handler {
|
||||
my ($self, %p) = @_;
|
||||
$p{header_params}->{'X-TargetApp-apiKey'} = $api_key;
|
||||
$p{header_params}->{'X-TargetApp-secretKey'} = $secret_key;
|
||||
}
|
||||
|
||||
# somewhere else...
|
||||
|
||||
my $api = MyApp->new;
|
||||
|
||||
my $pet = $api->get_pet_by_id(pet_id => $pet_id);
|
||||
|
||||
|
||||
So, C<auth_setup_handler()> will be called on your C<$api> object and passed the
|
||||
following parameters:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<header_params>
|
||||
|
||||
A hashref that will become the request headers. You can insert auth
|
||||
parameters.
|
||||
|
||||
=item C<query_params>
|
||||
|
||||
A hashref that will be encoded into the request URL. You can insert auth
|
||||
parameters.
|
||||
|
||||
=item C<auth_settings>
|
||||
|
||||
TODO. Probably not necessary?
|
||||
|
||||
=item C<api_client>
|
||||
|
||||
A reference to the C<WWW::SwaggerClient::ApiClient> object that is responsible
|
||||
for communicating with the server. Just in case that's useful.
|
||||
|
||||
=back
|
||||
|
||||
=head2 base_url
|
||||
=head2 C<base_url>
|
||||
|
||||
The generated code has the C<base_url> already set as a default value. This method
|
||||
returns (and optionally sets, but only if the API client has not been
|
||||
created yet) the current value of C<base_url>.
|
||||
|
||||
=head2 api_factory
|
||||
=head2 C<api_factory>
|
||||
|
||||
Returns an API factory object. You probably won't need to call this directly.
|
||||
|
||||
$self->api_factory('Pet'); # returns a WWW::SwaggerClient::PetApi instance
|
||||
|
||||
$self->pet_api; # the same
|
||||
$self->pet_api; # the same
|
||||
|
||||
=head1 MISSING METHODS
|
||||
|
||||
@ -280,13 +270,13 @@ Additional documentation for each class and method may be provided by the Swagge
|
||||
spec. If so, this is available via the C<class_documentation()> and
|
||||
C<method_documentation()> methods on each generated API and class:
|
||||
|
||||
my $cdoc = $api->pet_api->class_documentation;
|
||||
my $cdoc = $api->pet_api->class_documentation;
|
||||
my $cmdoc = $api->pet_api->method_documentation->{$method_name};
|
||||
|
||||
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation;
|
||||
my $odoc = $api->get_pet_by_id->(pet_id => $pet_id)->class_documentation;
|
||||
my $omdoc = $api->get_pet_by_id->(pet_id => $pet_id)->method_documentation->{method_name};
|
||||
|
||||
Each of these calls returns a hashref with various useful pieces of information.
|
||||
Each of these calls returns a hashref with various useful pieces of information.
|
||||
|
||||
=cut
|
||||
|
||||
|
@ -97,7 +97,7 @@ sub get_inventory {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = ['api_key'];
|
||||
my $auth_settings = [qw(api_key )];
|
||||
|
||||
# make the API Call
|
||||
my $response = $self->{api_client}->call_api($_resource_path, $_method,
|
||||
@ -164,7 +164,7 @@ sub place_order {
|
||||
}
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
my $response = $self->{api_client}->call_api($_resource_path, $_method,
|
||||
@ -238,7 +238,7 @@ sub get_order_by_id {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
my $response = $self->{api_client}->call_api($_resource_path, $_method,
|
||||
@ -312,7 +312,7 @@ sub delete_order {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
|
||||
|
@ -106,7 +106,7 @@ sub create_user {
|
||||
}
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
|
||||
@ -170,7 +170,7 @@ sub create_users_with_array_input {
|
||||
}
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
|
||||
@ -234,7 +234,7 @@ sub create_users_with_list_input {
|
||||
}
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
|
||||
@ -307,7 +307,7 @@ sub login_user {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
my $response = $self->{api_client}->call_api($_resource_path, $_method,
|
||||
@ -365,7 +365,7 @@ sub logout_user {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
|
||||
@ -436,7 +436,7 @@ sub get_user_by_name {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
my $response = $self->{api_client}->call_api($_resource_path, $_method,
|
||||
@ -519,7 +519,7 @@ sub update_user {
|
||||
}
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
|
||||
@ -590,7 +590,7 @@ sub delete_user {
|
||||
|
||||
|
||||
# authentication setting, if any
|
||||
my $auth_settings = [];
|
||||
my $auth_settings = [qw()];
|
||||
|
||||
# make the API Call
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use Test::More tests => 21;
|
||||
use Test::More tests => 29;
|
||||
use Test::Exception;
|
||||
use Test::Warnings 'warnings';
|
||||
use Test::Deep;
|
||||
@ -15,7 +15,7 @@ SKIP: {
|
||||
sub auth_setup_handler {}
|
||||
";
|
||||
|
||||
skip 'Moose not installed', 21 if $@;
|
||||
skip 'Moose not installed', 29 if $@;
|
||||
|
||||
|
||||
my $api;
|
||||
@ -76,5 +76,65 @@ my $pet_class_doco = { 'description' => '' };
|
||||
is_deeply($get_pet->class_documentation, $pet_class_doco, 'Pet object class_documentation is available');
|
||||
# / documentation tests
|
||||
|
||||
my $tokens = {
|
||||
username => 'UserName',
|
||||
password => 'PassWord',
|
||||
access_token => 'OAuth_token',
|
||||
|
||||
someKey => { token => 'some_key_token',
|
||||
prefix => 'some_key_prefix',
|
||||
in => 'query',
|
||||
},
|
||||
|
||||
anotherKey => { token => 'another_key_token',
|
||||
},
|
||||
};
|
||||
|
||||
$api->_cfg->accept_tokens({%$tokens}); # pass a copy
|
||||
no warnings 'once';
|
||||
is $WWW::SwaggerClient::Configuration::username, 'UserName', 'accept_tokens() correctly set the username';
|
||||
is $WWW::SwaggerClient::Configuration::password, 'PassWord', 'accept_tokens() correctly set the password';
|
||||
is $WWW::SwaggerClient::Configuration::access_token, 'OAuth_token', 'accept_tokens() correctly set the oauth';
|
||||
|
||||
my $api_key_href = {
|
||||
'anotherKey' => 'another_key_token',
|
||||
'someKey' => 'some_key_token'
|
||||
};
|
||||
cmp_deeply( $WWW::SwaggerClient::Configuration::api_key, $api_key_href, 'accept_tokens() correctly set api_key' );
|
||||
|
||||
my $api_key_prefix_href = {
|
||||
'someKey' => 'some_key_prefix'
|
||||
};
|
||||
cmp_deeply( $WWW::SwaggerClient::Configuration::api_key_prefix, $api_key_prefix_href, 'accept_tokens() correctly set api_key_prefix' );
|
||||
|
||||
my $api_key_in = {
|
||||
'someKey' => 'query',
|
||||
'anotherKey' => 'head'
|
||||
};
|
||||
cmp_deeply( $WWW::SwaggerClient::Configuration::api_key_in, $api_key_in, 'accept_tokens() correctly set api_key_in' );
|
||||
|
||||
use warnings 'once';
|
||||
|
||||
my $cleared_tokens_cmp = {
|
||||
'anotherKey' => {
|
||||
'in' => 'head',
|
||||
'token' => 'another_key_token',
|
||||
'prefix' => undef
|
||||
},
|
||||
'access_token' => 'OAuth_token',
|
||||
'someKey' => {
|
||||
'token' => 'some_key_token',
|
||||
'in' => 'query',
|
||||
'prefix' => 'some_key_prefix'
|
||||
},
|
||||
'username' => 'UserName',
|
||||
'password' => 'PassWord'
|
||||
};
|
||||
cmp_deeply( $api->_cfg->clear_tokens, $cleared_tokens_cmp, 'clear_tokens() returns the correct data structure' );
|
||||
|
||||
my $bad_token = { bad_token_name => 'bad token value' }; # value should should be hashref
|
||||
dies_ok { $api->_cfg->accept_tokens($bad_token) } "bad token causes exception";
|
||||
|
||||
|
||||
} # / SKIP
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user