oauth.py 4.55 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
19
20
21
22
23
24
25
26
27

from tornado.web import RequestHandler
import tornado.escape
import logging

import zoe_lib.config as config
import zoe_api.exceptions

import oauth2.grant
import json
import requests
28
29
30
31
32
import psycopg2

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
from zoe_api.api_endpoint import APIEndpoint
jenkins's avatar
jenkins committed
33
34
35
36
37
38
39
40

log = logging.getLogger(__name__)

"""

Example of using:

*To request a new token of type:
41
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
42
43
Output: {"token_type": "Bearer", "access_token": "3ddbe9ba-6a21-4e4d-993b-70556390c5d3", "refresh_token": "9bab190f-e211-42aa-917e-20ce987e355e", "expires_in": 36000}

44
*To refresh a token
45
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", "refresh_token": "9bab190f-e211-42aa-917e-20ce987e355e"}'
jenkins's avatar
jenkins committed
46
47
Output: {"token_type": "Bearer", "access_token": "378f8d5f-2eb5-4181-b632-ad23c4534d32", "expires_in": 36000}

48
49
*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
50
51
52
53
54
55
56
57
58
59
60
61
62

*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
63
        self.client_store = client_store
jenkins's avatar
jenkins committed
64
65
66
67
68
69

    @catch_exceptions
    def post(self):
        """REQUEST/REFRESH token"""
        uid, role = get_auth(self)
        
70
        grant_type = oauth2.grant.RefreshToken.grant_type + ':' + oauth2.grant.ResourceOwnerGrant.grant_type
jenkins's avatar
jenkins committed
71
        try:
72
73
74
            self.client_store.save_client(uid, '', role, '', grant_type, '')
        except psycopg2.IntegrityError as e:
            log.warn('User is already had')
jenkins's avatar
jenkins committed
75
        
76
        response = self._dispatch_request(uid)
jenkins's avatar
jenkins committed
77
78
        self._map_response(response)

79
    def _dispatch_request(self, uid):
jenkins's avatar
jenkins committed
80
        request = self.request
81
82
        params = json.loads(request.body.decode())

83
84
85
86
87
88
        if params['grant_type'] == 'refresh_token':
            auth_header = self.request.headers.get('Authorization')
            refresh_token = auth_header[7:]
            params['refresh_token'] = refresh_token


89
90
91
92
93
94
95
        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
96
        return self.auth_controller.dispatch(request, environ={})
97

jenkins's avatar
jenkins committed
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
    
    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

class OAuthRevokeAPI(RequestHandler):

    def initialize(self, **kwargs):
        """Initializes the request handler."""
        self.api_endpoint = kwargs['api_endpoint']  # type: APIEndpoint
        self.auth_controller = auth_controller
118
        self.token_store = token_store
jenkins's avatar
jenkins committed
119
120
121
122
123
124

    @catch_exceptions
    def delete(self, token):
        """DELETE token (logout)"""
        uid, role = get_auth(self)
        
125
        res = self.token_store.delete_refresh_token(token)
jenkins's avatar
jenkins committed
126
127

        if res == 0:
128
129
130
            ret = {'ret' :'No token found in database.'}
        else:
            ret = {'res': 'Revoked token.'}
jenkins's avatar
jenkins committed
131
        self.write(ret)