oauth.py 4.38 KB
Newer Older
jenkins's avatar
jenkins committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Copyright (c) 2016, Daniele Venzano
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

16
"""The oAuth2 API endpoints."""
jenkins's avatar
jenkins committed
17
18

import logging
hxquangnhat's avatar
hxquangnhat committed
19
20
import json
import psycopg2
jenkins's avatar
jenkins committed
21

hxquangnhat's avatar
hxquangnhat committed
22
from tornado.web import RequestHandler
jenkins's avatar
jenkins committed
23
24

import oauth2.grant
25
26
27

from zoe_api.rest_api.utils import catch_exceptions, get_auth
from zoe_api.rest_api.oauth_utils import auth_controller, client_store, token_store
jenkins's avatar
jenkins committed
28
29
30
31
32
33
34
35

log = logging.getLogger(__name__)

"""

Example of using:

*To request a new token of type:
36
Input: curl -u 'admin:admin' http://localhost:5001/api/0.6/oauth/token -X POST -H 'Content-Type: application/json' -d '{"grant_type": "password"}'
jenkins's avatar
jenkins committed
37
38
Output: {"token_type": "Bearer", "access_token": "3ddbe9ba-6a21-4e4d-993b-70556390c5d3", "refresh_token": "9bab190f-e211-42aa-917e-20ce987e355e", "expires_in": 36000}

39
*To refresh a token
qhoangxuan's avatar
qhoangxuan committed
40
Input: curl  -H 'Authorization: Bearer 9bab190f-e211-42aa-917e-20ce987e355e' http://localhost:5001/api/0.6/oauth/token -X POST -H 'Content-Type: application/json' -d '{"grant_type": "refresh_token"}'
jenkins's avatar
jenkins committed
41
42
Output: {"token_type": "Bearer", "access_token": "378f8d5f-2eb5-4181-b632-ad23c4534d32", "expires_in": 36000}

43
44
*To revoke a token, the passed token could be the access token or refresh token
curl -u 'admin:admin' -X DELETE http://localhost:5001/api/0.6/oauth/revoke/378f8d5f-2eb5-4181-b632-ad23c4534d32
jenkins's avatar
jenkins committed
45
46
47
48
49
50
51
52
53
54
55
56
57

*To authenticate with other rest api services, using a header with: "Authorization: Bearer access_token"
curl -H 'Authorization: Bearer 378f8d5f-2eb5-4181-b632-ad23c4534d32' http://localhost:5001/api/0.6/execution

"""

class OAuthGetAPI(RequestHandler):
    """The OAuthGetAPI endpoint."""

    def initialize(self, **kwargs):
        """Initializes the request handler."""
        self.api_endpoint = kwargs['api_endpoint']  # type: APIEndpoint
        self.auth_controller = auth_controller
58
        self.client_store = client_store
jenkins's avatar
jenkins committed
59
60
61
62
63

    @catch_exceptions
    def post(self):
        """REQUEST/REFRESH token"""
        uid, role = get_auth(self)
hxquangnhat's avatar
hxquangnhat committed
64

65
        grant_type = oauth2.grant.RefreshToken.grant_type + ':' + oauth2.grant.ResourceOwnerGrant.grant_type
qhoangxuan's avatar
qhoangxuan committed
66

jenkins's avatar
jenkins committed
67
        try:
68
            self.client_store.save_client(uid, '', role, '', grant_type, '')
hxquangnhat's avatar
hxquangnhat committed
69
70
        except psycopg2.IntegrityError:
            log.info('User is already had')
qhoangxuan's avatar
qhoangxuan committed
71

72
        response = self._dispatch_request(uid)
jenkins's avatar
jenkins committed
73
74
        self._map_response(response)

75
    def _dispatch_request(self, uid):
jenkins's avatar
jenkins committed
76
        request = self.request
77
78
        params = json.loads(request.body.decode())

79
80
81
82
83
        if params['grant_type'] == 'refresh_token':
            auth_header = self.request.headers.get('Authorization')
            refresh_token = auth_header[7:]
            params['refresh_token'] = refresh_token

84
85
86
87
88
89
90
        params['password'] = ''
        params['username'] = ''
        params['client_secret'] = ''
        params['scope'] = ''
        params['client_id'] = uid

        request.post_param = lambda key: params[key]
jenkins's avatar
jenkins committed
91
        return self.auth_controller.dispatch(request, environ={})
92

jenkins's avatar
jenkins committed
93
94
95
96
97
98
99
100
101
102
103
104
105
    def _map_response(self, response):
        for name, value in list(response.headers.items()):
            self.set_header(name, value)
        self.set_status(response.status_code)

        if response.status_code == 200:
            log.info("New token granted...")

        self.write(response.body)

    def data_received(self, chunk):
        pass

hxquangnhat's avatar
hxquangnhat committed
106
107
class OAuthRevokeAPI(RequestHandler): # pylint: disable=abstract-method
    """The OAuthRevokeAPI endpoint."""
jenkins's avatar
jenkins committed
108
109
110
111
112

    def initialize(self, **kwargs):
        """Initializes the request handler."""
        self.api_endpoint = kwargs['api_endpoint']  # type: APIEndpoint
        self.auth_controller = auth_controller
113
        self.token_store = token_store
jenkins's avatar
jenkins committed
114
115
116
117

    @catch_exceptions
    def delete(self, token):
        """DELETE token (logout)"""
hxquangnhat's avatar
hxquangnhat committed
118
119
        get_auth(self)

120
        res = self.token_store.delete_refresh_token(token)
jenkins's avatar
jenkins committed
121
122

        if res == 0:
123
124
125
            ret = {'ret' :'No token found in database.'}
        else:
            ret = {'res': 'Revoked token.'}
jenkins's avatar
jenkins committed
126
        self.write(ret)