#1036 skip API login for trust_remote_user, trust_x_remote_user, no_auth
This commit is contained in:
@@ -27,13 +27,14 @@ __PACKAGE__->result_source_instance->view_definition(<<ENDSQL
|
|||||||
WHERE tacacs
|
WHERE tacacs
|
||||||
UNION
|
UNION
|
||||||
SELECT username, 'api' AS role FROM users
|
SELECT username, 'api' AS role FROM users
|
||||||
WHERE token IS NOT NULL AND token_from IS NOT NULL
|
WHERE ( ? ::boolean = false ) OR
|
||||||
AND token_from > (EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) - ?)
|
( token IS NOT NULL AND token_from IS NOT NULL
|
||||||
|
AND token_from > (EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) - ?) )
|
||||||
UNION
|
UNION
|
||||||
SELECT username, 'api_admin' AS role FROM users
|
SELECT username, 'api_admin' AS role FROM users
|
||||||
WHERE token IS NOT NULL AND token_from IS NOT NULL
|
WHERE admin AND (( ? ::boolean = false ) OR
|
||||||
AND token_from > (EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) - ?)
|
( token IS NOT NULL AND token_from IS NOT NULL
|
||||||
AND admin
|
AND token_from > (EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) - ?) ))
|
||||||
ENDSQL
|
ENDSQL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -391,6 +391,10 @@ hook 'after' => sub {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
my $api_requires_key =
|
||||||
|
(setting('trust_remote_user') or setting('trust_x_remote_user') or setting('no_auth'))
|
||||||
|
eq '1' ? false : true;
|
||||||
|
|
||||||
# setup for swagger API
|
# setup for swagger API
|
||||||
my $swagger = Dancer::Plugin::Swagger->instance;
|
my $swagger = Dancer::Plugin::Swagger->instance;
|
||||||
my $swagger_doc = $swagger->doc;
|
my $swagger_doc = $swagger->doc;
|
||||||
@@ -398,8 +402,8 @@ my $swagger_doc = $swagger->doc;
|
|||||||
$swagger_doc->{consumes} = 'application/json';
|
$swagger_doc->{consumes} = 'application/json';
|
||||||
$swagger_doc->{produces} = 'application/json';
|
$swagger_doc->{produces} = 'application/json';
|
||||||
$swagger_doc->{tags} = [
|
$swagger_doc->{tags} = [
|
||||||
{name => 'General',
|
($api_requires_key ?
|
||||||
description => 'Log in and Log out'},
|
({name => 'General', description => 'Log in and Log out'}) : ()),
|
||||||
{name => 'Search',
|
{name => 'Search',
|
||||||
description => 'Search Operations'},
|
description => 'Search Operations'},
|
||||||
{name => 'Objects',
|
{name => 'Objects',
|
||||||
@@ -409,13 +413,16 @@ $swagger_doc->{tags} = [
|
|||||||
{name => 'Queue',
|
{name => 'Queue',
|
||||||
description => 'Operations on the Job Queue'},
|
description => 'Operations on the Job Queue'},
|
||||||
];
|
];
|
||||||
$swagger_doc->{securityDefinitions} = {
|
|
||||||
APIKeyHeader =>
|
if ($api_requires_key) {
|
||||||
{ type => 'apiKey', name => 'Authorization', in => 'header' },
|
$swagger_doc->{securityDefinitions} = {
|
||||||
BasicAuth =>
|
APIKeyHeader =>
|
||||||
{ type => 'basic' },
|
{ type => 'apiKey', name => 'Authorization', in => 'header' },
|
||||||
};
|
BasicAuth =>
|
||||||
$swagger_doc->{security} = [ { APIKeyHeader => [] } ];
|
{ type => 'basic' },
|
||||||
|
};
|
||||||
|
$swagger_doc->{security} = [ { APIKeyHeader => [] } ];
|
||||||
|
}
|
||||||
|
|
||||||
# manually install Swagger UI routes because plugin doesn't handle non-root
|
# manually install Swagger UI routes because plugin doesn't handle non-root
|
||||||
# hosting, so we cannot use show_ui(1)
|
# hosting, so we cannot use show_ui(1)
|
||||||
|
|||||||
@@ -95,9 +95,19 @@ sub get_user_roles {
|
|||||||
my $roles = $settings->{roles_relationship} || 'roles';
|
my $roles = $settings->{roles_relationship} || 'roles';
|
||||||
my $role_column = $settings->{role_column} || 'role';
|
my $role_column = $settings->{role_column} || 'role';
|
||||||
|
|
||||||
|
# this method returns a list of current user roles
|
||||||
|
# but for API with trust_remote_user, trust_x_remote_user, and no_auth
|
||||||
|
# we need to fake that there is a valid API key
|
||||||
|
|
||||||
|
my $api_requires_key =
|
||||||
|
(setting('trust_remote_user') or setting('trust_x_remote_user') or setting('no_auth'))
|
||||||
|
eq '1' ? 'false' : 'true';
|
||||||
|
|
||||||
return [ try {
|
return [ try {
|
||||||
$user->$roles->search({}, { bind => [setting('api_token_lifetime'), setting('api_token_lifetime')] })
|
$user->$roles->search({}, { bind => [
|
||||||
->get_column( $role_column )->all;
|
$api_requires_key, setting('api_token_lifetime'),
|
||||||
|
$api_requires_key, setting('api_token_lifetime'),
|
||||||
|
] })->get_column( $role_column )->all;
|
||||||
} ];
|
} ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,22 +32,11 @@ hook 'before' => sub {
|
|||||||
# from the internals of Dancer::Plugin::Auth::Extensible
|
# from the internals of Dancer::Plugin::Auth::Extensible
|
||||||
my $provider = Dancer::Plugin::Auth::Extensible::auth_provider('users');
|
my $provider = Dancer::Plugin::Auth::Extensible::auth_provider('users');
|
||||||
|
|
||||||
# API calls must conform strictly to path and header requirements
|
# Dancer will issue a cookie to the client which could be returned and
|
||||||
if (request_is_api) {
|
# cause API calls to succeed without passing token. Kill the session.
|
||||||
# Dancer will issue a cookie to the client which could be returned and
|
session->destroy if request_is_api;
|
||||||
# cause API calls to succeed without passing token. Kill the session.
|
|
||||||
session->destroy;
|
|
||||||
|
|
||||||
my $token = request->header('Authorization');
|
# ...otherwise, we can short circuit if Dancer reads its cookie OK
|
||||||
my $user = $provider->validate_api_token($token)
|
|
||||||
or return;
|
|
||||||
|
|
||||||
session(logged_in_user => $user);
|
|
||||||
session(logged_in_user_realm => 'users');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
# after checking API, we can short circuit if Dancer reads its cookie OK
|
|
||||||
return if session('logged_in_user');
|
return if session('logged_in_user');
|
||||||
|
|
||||||
if (setting('trust_x_remote_user')
|
if (setting('trust_x_remote_user')
|
||||||
@@ -72,27 +61,27 @@ hook 'before' => sub {
|
|||||||
session(logged_in_user => $user);
|
session(logged_in_user => $user);
|
||||||
session(logged_in_user_realm => 'users');
|
session(logged_in_user_realm => 'users');
|
||||||
}
|
}
|
||||||
|
# this works for API calls, too
|
||||||
elsif (setting('no_auth')) {
|
elsif (setting('no_auth')) {
|
||||||
session(logged_in_user => 'guest');
|
session(logged_in_user => 'guest');
|
||||||
session(logged_in_user_realm => 'users');
|
session(logged_in_user_realm => 'users');
|
||||||
}
|
}
|
||||||
|
# API calls must conform strictly to path and header requirements
|
||||||
|
elsif (request_is_api) {
|
||||||
|
my $token = request->header('Authorization');
|
||||||
|
my $user = $provider->validate_api_token($token)
|
||||||
|
or return;
|
||||||
|
|
||||||
|
session(logged_in_user => $user);
|
||||||
|
session(logged_in_user_realm => 'users');
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
# user has no AuthN - force to handler for '/'
|
# user has no AuthN - force to handler for '/'
|
||||||
request->path_info('/');
|
request->path_info('/');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
# override default login_handler so we can log access in the database
|
my $login_sub = sub {
|
||||||
swagger_path {
|
|
||||||
description => 'Obtain an API Key',
|
|
||||||
tags => ['General'],
|
|
||||||
path => (setting('url_base') ? setting('url_base')->with('/login')->path : '/login'),
|
|
||||||
parameters => [],
|
|
||||||
responses => { default => { examples => {
|
|
||||||
'application/json' => { api_key => 'cc9d5c02d8898e5728b7d7a0339c0785' } } },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
post '/login' => sub {
|
|
||||||
my $api = ((request->accept and request->accept =~ m/(?:json|javascript)/) ? true : false);
|
my $api = ((request->accept and request->accept =~ m/(?:json|javascript)/) ? true : false);
|
||||||
|
|
||||||
# get authN data from BasicAuth header used by API, put into params
|
# get authN data from BasicAuth header used by API, put into params
|
||||||
@@ -161,21 +150,7 @@ post '/login' => sub {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
# ugh, *puke*, but D::P::Swagger has no way to set this with swagger_path
|
my $logout_sub = sub {
|
||||||
# must be after the path is declared, above.
|
|
||||||
Dancer::Plugin::Swagger->instance->doc
|
|
||||||
->{paths}->{ (setting('url_base') ? setting('url_base')->with('/login')->path : '/login') }
|
|
||||||
->{post}->{security}->[0]->{BasicAuth} = [];
|
|
||||||
|
|
||||||
# we override the default login_handler, so logout has to be handled as well
|
|
||||||
swagger_path {
|
|
||||||
description => 'Destroy user API Key and session cookie',
|
|
||||||
tags => ['General'],
|
|
||||||
path => (setting('url_base') ? setting('url_base')->with('/logout')->path : '/logout'),
|
|
||||||
parameters => [],
|
|
||||||
responses => { default => { examples => { 'application/json' => {} } } },
|
|
||||||
},
|
|
||||||
get '/logout' => sub {
|
|
||||||
my $api = ((request->accept and request->accept =~ m/(?:json|javascript)/) ? true : false);
|
my $api = ((request->accept and request->accept =~ m/(?:json|javascript)/) ? true : false);
|
||||||
|
|
||||||
# clear out API token
|
# clear out API token
|
||||||
@@ -202,6 +177,44 @@ get '/logout' => sub {
|
|||||||
redirect uri_for(setting('web_home'))->path;
|
redirect uri_for(setting('web_home'))->path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
my $api_requires_key =
|
||||||
|
(setting('trust_remote_user') or setting('trust_x_remote_user') or setting('no_auth'))
|
||||||
|
eq '1' ? false : true;
|
||||||
|
|
||||||
|
if ($api_requires_key) {
|
||||||
|
# override default login_handler so we can log access in the database
|
||||||
|
swagger_path {
|
||||||
|
description => 'Obtain an API Key',
|
||||||
|
tags => ['General'],
|
||||||
|
path => (setting('url_base') ? setting('url_base')->with('/login')->path : '/login'),
|
||||||
|
parameters => [],
|
||||||
|
responses => { default => { examples => {
|
||||||
|
'application/json' => { api_key => 'cc9d5c02d8898e5728b7d7a0339c0785' } } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
post '/login' => $login_sub;
|
||||||
|
|
||||||
|
# ugh, *puke*, but D::P::Swagger has no way to set this with swagger_path
|
||||||
|
# must be after the path is declared, above.
|
||||||
|
Dancer::Plugin::Swagger->instance->doc
|
||||||
|
->{paths}->{ (setting('url_base') ? setting('url_base')->with('/login')->path : '/login') }
|
||||||
|
->{post}->{security}->[0]->{BasicAuth} = [];
|
||||||
|
|
||||||
|
# we override the default login_handler, so logout has to be handled as well
|
||||||
|
swagger_path {
|
||||||
|
description => 'Destroy user API Key and session cookie',
|
||||||
|
tags => ['General'],
|
||||||
|
path => (setting('url_base') ? setting('url_base')->with('/logout')->path : '/logout'),
|
||||||
|
parameters => [],
|
||||||
|
responses => { default => { examples => { 'application/json' => {} } } },
|
||||||
|
},
|
||||||
|
get '/logout' => $logout_sub;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
post '/login' => $login_sub;
|
||||||
|
get '/logout' => $logout_sub;
|
||||||
|
}
|
||||||
|
|
||||||
# user redirected here when require_role does not succeed
|
# user redirected here when require_role does not succeed
|
||||||
any qr{^/(?:login(?:/denied)?)?} => sub {
|
any qr{^/(?:login(?:/denied)?)?} => sub {
|
||||||
my $api = ((request->accept and request->accept =~ m/(?:json|javascript)/) ? true : false);
|
my $api = ((request->accept and request->accept =~ m/(?:json|javascript)/) ? true : false);
|
||||||
|
|||||||
Reference in New Issue
Block a user