Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
nomad-lab
nomad-FAIR
Commits
6be247ee
Commit
6be247ee
authored
Dec 22, 2018
by
Markus Scheidgen
Browse files
Refactored api auth part to proper restplus.
parent
7df3283d
Changes
3
Hide whitespace changes
Inline
Side-by-side
nomad/api/app.py
View file @
6be247ee
...
...
@@ -38,19 +38,8 @@ app.config.setdefault('RESTPLUS_MASK_SWAGGER', False)
CORS
(
app
)
authorizations
=
{
'HTTP Basic'
:
{
'type'
:
'basic'
},
'X-Token'
:
{
'type'
:
'apiKey'
,
'in'
:
'header'
,
'name'
:
'X-Token'
}
}
api
=
Api
(
app
,
version
=
'1.0'
,
title
=
'nomad@FAIRDI API'
,
authorizations
=
authorizations
,
app
,
version
=
'1.0'
,
title
=
'nomad@FAIRDI API'
,
description
=
'Official API for nomad@FAIRDI services.'
)
""" Provides the flask restplust api instance """
...
...
nomad/api/auth.py
View file @
6be247ee
...
...
@@ -35,12 +35,12 @@ authenticated user information for authorization or otherwise.
.. autofunction:: login_really_required
"""
from
flask
import
g
,
request
from
flask_restplus
import
abort
from
flask
import
g
,
request
,
make_response
from
flask_restplus
import
abort
,
Resource
from
flask_httpauth
import
HTTPBasicAuth
from
nomad
import
config
from
nomad.coe_repo
import
User
from
nomad.coe_repo
import
User
,
LoginException
from
.app
import
app
,
api
,
base_path
...
...
@@ -48,6 +48,19 @@ app.config['SECRET_KEY'] = config.services.api_secret
auth
=
HTTPBasicAuth
()
# Authentication scheme definitions, for swagger only.
api
.
authorizations
=
{
'HTTP Basic'
:
{
'type'
:
'basic'
},
'X-Token'
:
{
'type'
:
'apiKey'
,
'in'
:
'header'
,
'name'
:
'X-Token'
}
}
@
auth
.
verify_password
def
verify_password
(
username_or_token
,
password
):
# first try to authenticate by token
...
...
@@ -70,6 +83,8 @@ def login_if_available(func):
A decorator for API endpoint implementations that might authenticate users, but
provide limited functionality even without users.
"""
@
api
.
response
(
401
,
'Not authorized, some data require authentication and authorization'
)
@
api
.
doc
(
security
=
list
(
api
.
authorizations
.
keys
()))
@
auth
.
login_required
def
wrapper
(
*
args
,
**
kwargs
):
# TODO the cutom X-Token based authentication should be replaced by a real
...
...
@@ -78,7 +93,7 @@ def login_if_available(func):
token
=
request
.
headers
[
'X-Token'
]
g
.
user
=
User
.
verify_auth_token
(
token
)
if
not
g
.
user
:
abort
(
401
,
message
=
'
Provided access token is not valid or does not exist.
'
)
abort
(
401
,
message
=
'
Not authorized, some data require authentication and authorization
'
)
return
func
(
*
args
,
**
kwargs
)
...
...
@@ -92,12 +107,12 @@ def login_really_required(func):
A decorator for API endpoint implementations that forces user authentication on
endpoints.
"""
@
api
.
response
(
401
,
'
N
ot
A
uthorized'
)
@
api
.
doc
(
security
=
[
'HTTP Basic'
]
)
@
api
.
response
(
401
,
'
Authentication required or n
ot
a
uthorized
to access requested data
'
)
@
api
.
doc
(
security
=
list
(
api
.
authorizations
.
keys
())
)
@
login_if_available
def
wrapper
(
*
args
,
**
kwargs
):
if
g
.
user
is
None
:
abort
(
401
,
message
=
'A
nonymous access is forbidden, authorization required
'
)
abort
(
401
,
message
=
'A
uthentication required or not authorized to access requested data
'
)
else
:
return
func
(
*
args
,
**
kwargs
)
wrapper
.
__name__
=
func
.
__name__
...
...
@@ -105,20 +120,30 @@ def login_really_required(func):
return
wrapper
@
app
.
route
(
'%s/token'
%
base_path
)
@
login_really_required
def
get_auth_token
():
"""
Get a token for authenticated users. This is currently disabled and all authentication
matters are solved by the NOMAD-coe repository GUI.
ns
=
api
.
namespace
(
'%s/auth'
%
base_path
[
1
:]
if
base_path
is
not
''
else
'auth'
,
description
=
'Authentication related endpoints.'
)
.. :quickref: Get a token to authenticate the user in follow up requests.
:resheader Content-Type: application/json
:status 200: calc successfully retrieved
:returns: an authentication token that is valid for 10 minutes.
"""
assert
False
,
'All authorization is none via NOMAD-coe repository GUI'
# TODO all authorization is done via NOMAD-coe repository GUI
# token = g.user.generate_auth_token(600)
# return jsonify({'token': token.decode('ascii'), 'duration': 600})
@
ns
.
route
(
'/token'
)
class
Token
(
Resource
):
@
api
.
response
(
200
,
'Token send'
,
headers
=
{
'Content-Type'
:
'text/plain; charset=utf-8'
})
@
login_really_required
def
get
(
self
):
"""
Get the access token for the authenticated user.
You can use basic authentication to access this endpoint and receive a
token for further api access. This token will expire at some point and presents
a more secure method of authentication.
"""
try
:
response
=
make_response
(
g
.
user
.
get_auth_token
().
decode
(
'utf-8'
))
response
.
headers
[
'Content-Type'
]
=
'text/plain; charset=utf-8'
return
response
except
LoginException
:
abort
(
401
,
message
=
'You are not propertly logged in at the NOMAD coe repository, '
'there is no token for you.'
)
tests/test_api.py
View file @
6be247ee
...
...
@@ -19,6 +19,7 @@ config.services = config.NomadServicesConfig(**services_config)
from
nomad
import
api
# noqa
from
nomad.files
import
UploadFile
# noqa
from
nomad.processing
import
Upload
# noqa
from
nomad.coe_repo
import
User
from
tests.processing.test_data
import
example_files
# noqa
from
tests.test_files
import
example_file
,
example_file_mainfile
,
example_file_contents
# noqa
...
...
@@ -53,17 +54,17 @@ def create_auth_headers(user):
@
pytest
.
fixture
(
scope
=
'session'
)
def
test_user_auth
(
test_user
):
def
test_user_auth
(
test_user
:
User
):
return
create_auth_headers
(
test_user
)
@
pytest
.
fixture
(
scope
=
'session'
)
def
test_other_user_auth
(
other_test_user
):
def
test_other_user_auth
(
other_test_user
:
User
):
return
create_auth_headers
(
other_test_user
)
class
TestAuth
:
def
test_xtoken_auth
(
self
,
client
,
test_user
,
no_warn
):
def
test_xtoken_auth
(
self
,
client
,
test_user
:
User
,
no_warn
):
rv
=
client
.
get
(
'/uploads/'
,
headers
=
{
'X-Token'
:
test_user
.
email
# the test users have their email as tokens for convinience
})
...
...
@@ -88,6 +89,11 @@ class TestAuth:
})
assert
rv
.
status_code
==
401
def
test_get_token
(
self
,
client
,
test_user_auth
,
test_user
:
User
,
no_warn
):
rv
=
client
.
get
(
'/auth/token'
,
headers
=
test_user_auth
)
assert
rv
.
status_code
==
200
assert
rv
.
data
.
decode
(
'utf-8'
)
==
test_user
.
get_auth_token
().
decode
(
'utf-8'
)
class
TestUploads
:
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment