Projet

Général

Profil

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

oidc / ckanext / ozwillo_pyoidc / oidc.py @ cb408fc1

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

    
67
        if self.state != authresp['state']:
68
            raise OIDCError("Invalid state %s." % authresp["state"])
69

    
70
        if isinstance(authresp, ErrorResponse):
71
            return OIDCError("Access denied")
72

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

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

    
90
                atresp = self.do_access_token_request(
91
                    scope="openid", state=authresp["state"], request_args=args,
92
                    authn_method=self.registration_response["token_endpoint_auth_method"])
93
            except Exception as err:
94
                logger.error("%s" % err)
95
                raise
96

    
97
            if isinstance(atresp, ErrorResponse):
98
                raise OIDCError("Invalid response %s." % atresp["error"])
99

    
100
        inforesp = self.do_user_info_request(state=authresp["state"],
101
                                             behavior='use_authorization_header')
102

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

    
106
        userinfo = inforesp.to_dict()
107

    
108
        logger.debug("UserInfo: %s" % inforesp)
109

    
110
        return userinfo
111

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

    
129
    client = Client(client_authn_method=CLIENT_AUTHN_METHOD,
130
                    behaviour=kwargs["behaviour"],
131
                    verify_ssl=conf.VERIFY_SSL, **args)
132

    
133
    # The behaviour parameter is not significant for the election process
134
    _key_set.discard("behaviour")
135
    for param in ["allow"]:
136
        try:
137
            setattr(client, param, kwargs[param])
138
        except KeyError:
139
            pass
140
        else:
141
            _key_set.discard(param)
142

    
143
    if _key_set == set(["client_info"]):  # Everything dynamic
144
        # There has to be a userid
145
        if not userid:
146
            raise MissingAttribute("Missing userid specification")
147

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

    
181
    return client
(3-3/4)