Project

General

Profile

Download (6.47 KB) Statistics
| Branch: | Tag: | Revision:

oidc / ckanext / ozwillo_pyoidc / oidc.py @ c4dcef5d

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, session, acr_value=None):
30
        session["state"] = rndstr()
31
        session["nonce"] = rndstr()
32
        request_args = {
33
            "response_type": self.behaviour["response_type"],
34
            "scope": self.behaviour["scope"],
35
            "state": session["state"],
36
            "nonce": session["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 isinstance(authresp, ErrorResponse):
68
            return OIDCError("Access denied")
69

    
70
        try:
71
            self.id_token[authresp["state"]] = authresp["id_token"]
72
        except KeyError:
73
            pass
74

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

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

    
94
            if isinstance(atresp, ErrorResponse):
95
                raise OIDCError("Invalid response %s." % atresp["error"])
96

    
97
        inforesp = self.do_user_info_request(state=authresp["state"],
98
                                             behavior='use_authorization_header')
99

    
100
        if isinstance(inforesp, ErrorResponse):
101
            raise OIDCError("Invalid response %s." % inforesp["error"])
102

    
103
        userinfo = inforesp.to_dict()
104

    
105
        logger.debug("UserInfo: %s" % inforesp)
106

    
107
        return userinfo
108

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

    
126
    client = Client(client_authn_method=CLIENT_AUTHN_METHOD,
127
                    behaviour=kwargs["behaviour"],
128
                    verify_ssl=conf.VERIFY_SSL, **args)
129

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

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

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

    
178
    return client
(3-3/4)