Project

General

Profile

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

oidc / ckanext / ozwillo_pyoidc / oidc.py @ 34457e9c

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
        state = rndstr()
31
        nonce = rndstr()
32
        request_args = {
33
            "response_type": self.behaviour["response_type"],
34
            "scope": self.behaviour["scope"],
35
            "state": 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, state
55

    
56
    def callback(self, state, response):
57
        """
58
        This is the method that should be called when an AuthN response has been
59
        received from the OP.
60
        """
61
        authresp = self.parse_response(AuthorizationResponse, response,
62
                                       sformat="dict", keyjar=self.keyjar)
63
        app_admin = False
64
        app_user = False
65
        try:
66
            if state != authresp['state']:
67
                raise OIDCError("Invalid state %s." % authresp["state"])
68
        except AttributeError:
69
            raise OIDCError("access denied")
70

    
71
        if isinstance(authresp, ErrorResponse):
72
            raise OIDCError("Access denied")
73

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

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

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

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

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

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

    
110
        userinfo = inforesp.to_dict()
111

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

    
114
        return userinfo, app_admin, app_user, self.access_token, self.id_token
115

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

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

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

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

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

    
185
    return client
(3-3/4)