Projet

Général

Profil

Télécharger (6,84 ko) Statistiques
| Branche: | Tag: | Révision:

oidc / ckanext / ozwillo_pyoidc / oidc.py @ cf38fede

1
from oic.exception import MissingAttribute
2
from oic import oic
3
from oic.oauth2 import rndstr, ErrorResponse
4
from oic.oic import ProviderConfigurationResponse, AuthorizationResponse
5
from oic.oic import RegistrationResponse
6
from oic.oic import AuthorizationRequest
7
from oic.utils.authn.client import CLIENT_AUTHN_METHOD
8

    
9
import logging
10

    
11
logger = logging.getLogger(__name__)
12

    
13
import conf
14

    
15
class OIDCError(Exception):
16
    pass
17

    
18

    
19
class Client(oic.Client):
20
    def __init__(self, client_id=None, client_secret=None, ca_certs=None,
21
                 client_prefs=None, client_authn_method=None, keyjar=None,
22
                 verify_ssl=True, behaviour=None):
23
        oic.Client.__init__(self, client_id, client_secret, ca_certs,
24
                            client_prefs, client_authn_method,
25
                            keyjar, verify_ssl)
26
        if behaviour:
27
            self.behaviour = behaviour
28

    
29
    def create_authn_request(self, acr_value=None):
30
        self.state = rndstr()
31
        nonce = rndstr()
32
        request_args = {
33
            "response_type": self.behaviour["response_type"],
34
            "scope": self.behaviour["scope"],
35
            "state": self.state,
36
            "nonce": nonce,
37
            "redirect_uri": self.registration_response["redirect_uris"][0]
38
        }
39

    
40
        if acr_value is not None:
41
            request_args["acr_values"] = acr_value
42

    
43
        cis = self.construct_AuthorizationRequest(request_args=request_args)
44
        logger.debug("request: %s" % cis)
45

    
46
        url, body, ht_args, cis = self.uri_and_body(AuthorizationRequest, cis,
47
                                                    method="GET",
48
                                                    request_args=request_args)
49

    
50
        logger.debug("body: %s" % body)
51
        logger.info("URL: %s" % url)
52
        logger.debug("ht_args: %s" % ht_args)
53

    
54
        return str(url), ht_args
55

    
56
    def callback(self, response):
57
        """
58
        This is the method that should be called when an AuthN response has been
59
        received from the OP.
60

    
61
        :param response: The URL returned by the OP
62
        :return:
63
        """
64
        authresp = self.parse_response(AuthorizationResponse, response,
65
                                       sformat="dict", keyjar=self.keyjar)
66
        try:
67
            if self.state != authresp['state']:
68
                raise OIDCError("Invalid state %s." % authresp["state"])
69
        except AttributeError:
70
            raise OIDCError("access denied")
71

    
72
        if isinstance(authresp, ErrorResponse):
73
            return OIDCError("Access denied")
74

    
75
        try:
76
            self.id_token[authresp["state"]] = authresp["id_token"]
77
        except KeyError:
78
            pass
79

    
80
        if self.behaviour["response_type"] == "code":
81
            # get the access token
82
            try:
83
                args = {
84
                    "grant_type": "authorization_code",
85
                    "code": authresp["code"],
86
                    "redirect_uri": self.registration_response[
87
                        "redirect_uris"][0],
88
                    "client_id": self.client_id,
89
                    "client_secret": self.client_secret
90
                }
91

    
92
                atresp = self.do_access_token_request(
93
                    scope="openid", state=authresp["state"], request_args=args,
94
                    authn_method=self.registration_response["token_endpoint_auth_method"])
95
                id_token = atresp['id_token']
96
                self.app_admin = 'app_admin' in id_token and id_token['app_admin']
97
                self.app_user = 'app_user' in id_token  and id_token['app_user']
98
            except Exception as err:
99
                logger.error("%s" % err)
100
                raise
101

    
102
            if isinstance(atresp, ErrorResponse):
103
                raise OIDCError("Invalid response %s." % atresp["error"])
104

    
105
        inforesp = self.do_user_info_request(state=authresp["state"],
106
                                             behavior='use_authorization_header')
107

    
108
        if isinstance(inforesp, ErrorResponse):
109
            raise OIDCError("Invalid response %s." % inforesp["error"])
110

    
111
        userinfo = inforesp.to_dict()
112

    
113
        logger.debug("UserInfo: %s" % inforesp)
114

    
115
        return userinfo
116

    
117
def create_client(**kwargs):
118
    """
119
    kwargs = config.CLIENT.iteritems
120
    """
121
    _key_set = set(kwargs.keys())
122
    args = {}
123
    for param in ["verify_ssl", "client_id", "client_secret"]:
124
        try:
125
            args[param] = kwargs[param]
126
        except KeyError:
127
            try:
128
                args[param] = kwargs['client_registration'][param]
129
            except KeyError:
130
                pass
131
        else:
132
            _key_set.discard(param)
133

    
134
    client = Client(client_authn_method=CLIENT_AUTHN_METHOD,
135
                    behaviour=kwargs["behaviour"],
136
                    verify_ssl=conf.VERIFY_SSL, **args)
137

    
138
    # The behaviour parameter is not significant for the election process
139
    _key_set.discard("behaviour")
140
    for param in ["allow"]:
141
        try:
142
            setattr(client, param, kwargs[param])
143
        except KeyError:
144
            pass
145
        else:
146
            _key_set.discard(param)
147

    
148
    if _key_set == set(["client_info"]):  # Everything dynamic
149
        # There has to be a userid
150
        if not userid:
151
            raise MissingAttribute("Missing userid specification")
152

    
153
        # Find the service that provides information about the OP
154
        issuer = client.wf.discovery_query(userid)
155
        # Gather OP information
156
        _ = client.provider_config(issuer)
157
        # register the client
158
        _ = client.register(client.provider_info["registration_endpoint"],
159
                            **kwargs["client_info"])
160
    elif _key_set == set(["client_info", "srv_discovery_url"]):
161
        # Ship the webfinger part
162
        # Gather OP information
163
        _ = client.provider_config(kwargs["srv_discovery_url"])
164
        # register the client
165
        _ = client.register(client.provider_info["registration_endpoint"],
166
                            **kwargs["client_info"])
167
    elif _key_set == set(["provider_info", "client_info"]):
168
        client.handle_provider_config(
169
            ProviderConfigurationResponse(**kwargs["provider_info"]),
170
            kwargs["provider_info"]["issuer"])
171
        _ = client.register(client.provider_info["registration_endpoint"],
172
                            **kwargs["client_info"])
173
    elif _key_set == set(["provider_info", "client_registration"]):
174
        client.handle_provider_config(
175
            ProviderConfigurationResponse(**kwargs["provider_info"]),
176
            kwargs["provider_info"]["issuer"])
177
        client.store_registration_info(RegistrationResponse(
178
            **kwargs["client_registration"]))
179
    elif _key_set == set(["srv_discovery_url", "client_registration"]):
180
        _ = client.provider_config(kwargs["srv_discovery_url"])
181
        client.store_registration_info(RegistrationResponse(
182
            **kwargs["client_registration"]))
183
    else:
184
        raise Exception("Configuration error ?")
185

    
186
    return client
(3-3/4)