Skip to content

Commit da593ec

Browse files
committed
Merge branch 'master' of https://github.com/its-dirg/SATOSA
# Conflicts: # example/proxy_conf.yaml.example
2 parents b46affd + a81a53f commit da593ec

15 files changed

Lines changed: 82 additions & 82 deletions

File tree

doc/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ in the [example directory](../example).
2121
| Parameter name | Data type | Example value | Description |
2222
| -------------- | --------- | ------------- | ----------- |
2323
| `BASE` | string | `https://proxy.example.com` | base url of the proxy |
24-
| `SESSION_OPTS` | dict | `{session.type: memory, session.cookie_expires: Yes, session.auto: Yes}` | configuration options for [Beaker Session Middleware](http://beaker.readthedocs.org/en/latest/configuration.html)
2524
| `COOKIE_STATE_NAME` | string | `vopaas_state` | name of cooke VOPaaS uses for preserving state between requests |
2625
| `STATE_ENCRYPTION_KEY` | string | `52fddd3528a44157` | key used for encrypting the state cookie, will be overriden by the environment variable `SATOSA_STATE_ENCRYPTION_KEY` if it is set |
2726
| `INTERNAL_ATTRIBUTES` | string | `example/internal_attributes.yaml` | path to attribute mapping
@@ -32,6 +31,7 @@ in the [example directory](../example).
3231
| `USER_ID_HASH_SALT` | string | `61a89d2db0b9e1e2` | salt used when creating the persistent user identifier, will be overriden by the environment variable `SATOSA_USER_ID_HASH_SALT` if it is set |
3332
| `CONSENT` | dict | see configuration of [Additional Services](#additional-services) | optional configuration of consent service |
3433
| `ACCOUNT_LINKING` | dict | see configuration of [Additional Services](#additional-services) | optional configuration of account linking service |
34+
| `LOGGING` | dict | see [Python logging.conf](https://docs.python.org/3/library/logging.config.html) | optional configuration of application logging |
3535

3636

3737
#### Additional services

example/plugins/backends/saml2_backend.yaml.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ config:
2121
discovery_response:
2222
- [<base_url>/<name>/disco, 'urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol']
2323
xmlsec_binary: /usr/bin/xmlsec1
24+
# disco_srv must be defined if there is more than one IdP in the metadata specified above
2425
disco_srv: http://disco.example.com
2526
publish_metadata: <base_url>/<name>/metadata
2627
state_id: <name>

example/proxy_conf.yaml.example

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,27 @@ ACCOUNT_LINKING:
3232
LOGGING:
3333
version: 1
3434
formatters:
35-
standard:
35+
simple:
3636
format: "[%(asctime)-19.19s] [%(levelname)-5.5s]: %(message)s"
3737
handlers:
38-
default:
39-
level: "INFO"
40-
class: "logging.FileHandler"
41-
filename: "vopaas.log"
42-
formatter: "standard"
38+
console:
39+
class: logging.StreamHandler
40+
level: DEBUG
41+
formatter: simple
42+
stream: ext://sys.stdout
43+
info_file_handler:
44+
class: logging.handlers.RotatingFileHandler
45+
level: INFO
46+
formatter: simple
47+
filename: info.log
48+
maxBytes: 10485760 # 10MB
49+
backupCount: 20
50+
encoding: utf8
4351
loggers:
4452
satosa:
45-
handlers: ["default"]
46-
level: "INFO"
47-
propagate: Yes
48-
vopaas:
49-
handlers: ["default"]
50-
level: "INFO"
51-
propagate: Yes
52-
saml:
53-
handlers: ["default"]
54-
level: "WARN"
55-
propagate: Yes
56-
oic:
57-
handlers: ["default"]
58-
level: "WARN"
59-
propagate: Yes
53+
level: DEBUG
54+
handlers: [console]
55+
propagate: no
56+
root:
57+
level: INFO
58+
handlers: [info_file_handler]

requirements.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
setup(
1010
name='SATOSA',
11-
version='0.2',
11+
version='0.3',
1212
description='',
1313
author='DIRG',
1414
author_email='dirg@its.umu.se',
@@ -22,7 +22,7 @@
2222
"future",
2323
"oic",
2424
"pyjwkest",
25-
# "pysaml2 >= 3.0.2",
25+
"pysaml2 >= 4.0.0",
2626
"requests",
2727
"PyYAML",
2828
"pycrypto",

src/satosa/backends/saml2.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ def start_auth(self, context, internal_req):
9797
:type internal_req: satosa.internal_data.InternalRequest
9898
:rtype: satosa.response.Response
9999
"""
100+
101+
# if there is only one IdP in the metadata, bypass the discovery service
102+
idps = self.sp.metadata.identity_providers()
103+
if len(idps) == 1:
104+
return self.authn_request(context, idps[0], internal_req)
105+
100106
try:
101107
entity_id = context.internal_data["saml2.target_entity_id"]
102108
return self.authn_request(context, entity_id, internal_req)

tests/satosa/backends/test_oauth.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,8 @@
5656
'edupersontargetedid': {'saml': ['eduPersonTargetedID'], 'openid': ['sub'],
5757
'facebook': ['id']},
5858
'name': {'saml': ['cn'], 'openid': ['name'], 'facebook': ['name']},
59-
'address': {'openid': ['address->street_address'], 'saml': ['postaladdress']},
6059
'surname': {'saml': ['sn', 'surname'], 'openid': ['family_name'],
61-
'facebook': ['last_name']}}, 'separator': '->'}
60+
'facebook': ['last_name']}}}
6261

6362

6463
class TestFacebook:

tests/satosa/backends/test_openid_connect.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@
2222
'edupersontargetedid': {'saml': ['eduPersonTargetedID'], 'openid': ['sub'],
2323
'facebook': ['id']},
2424
'name': {'saml': ['cn'], 'openid': ['name'], 'facebook': ['name']},
25-
'address': {'openid': ['address->street_address'], 'saml': ['postaladdress']},
2625
'surname': {'saml': ['sn', 'surname'], 'openid': ['family_name'],
27-
'facebook': ['last_name']}}, 'separator': '->'}
26+
'facebook': ['last_name']}}}
2827

2928

3029
def verify_object_types_callback(context, response):

tests/satosa/backends/test_saml2.py

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
"""
22
Tests for the SAML frontend module src/backends/saml2.py.
33
"""
4-
from urllib import parse
5-
import re
64
import os.path
5+
import re
6+
from urllib.parse import urlparse, parse_qs, parse_qsl
77

8-
from saml2 import BINDING_HTTP_POST
8+
from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT
99
from saml2.authn_context import PASSWORD
1010
from saml2.config import IdPConfig
1111
from saml2.entity_category.edugain import COC
1212
from saml2.entity_category.swamid import RESEARCH_AND_EDUCATION, HEI, SFS_1993_1153, NREN, EU
13-
1413
from saml2.extension.idpdisc import BINDING_DISCO
15-
1614
from saml2.saml import NAME_FORMAT_URI, NAMEID_FORMAT_TRANSIENT, NAMEID_FORMAT_PERSISTENT
1715

1816
from satosa.backends.saml2 import SamlBackend
@@ -33,9 +31,8 @@
3331
'edupersontargetedid': {'saml': ['eduPersonTargetedID'], 'openid': ['sub'],
3432
'facebook': ['id']},
3533
'name': {'saml': ['cn'], 'openid': ['name'], 'facebook': ['name']},
36-
'address': {'openid': ['address->street_address'], 'saml': ['postaladdress']},
3734
'surname': {'saml': ['sn', 'surname'], 'openid': ['family_name'],
38-
'facebook': ['last_name']}}, 'separator': '->'}
35+
'facebook': ['last_name']}}}
3936

4037

4138
class TestConfiguration(object):
@@ -65,7 +62,7 @@ def __init__(self):
6562
"name": "Proxy IdP",
6663
"endpoints": {
6764
"single_sign_on_service": [
68-
("%s/sso/post" % idp_base, BINDING_HTTP_POST),
65+
("%s/sso/redirect" % idp_base, BINDING_HTTP_REDIRECT),
6966
],
7067
},
7168
"policy": {
@@ -122,6 +119,12 @@ def __init__(self):
122119
"sp_metadata")
123120
idp_metadata = FileGenerator.get_instance().create_metadata(self.idpconfig, "idp_metadata")
124121
self.spconfig["config"]["metadata"]["local"].append(idp_metadata.name)
122+
123+
idp2_config = self.idpconfig.copy()
124+
idp2_config["entityid"] = "just_an_extra_idp"
125+
idp_metadata2 = FileGenerator.get_instance().create_metadata(idp2_config, "idp2_metadata")
126+
self.spconfig["config"]["metadata"]["local"].append(idp_metadata2.name)
127+
125128
self.idpconfig["metadata"]["local"].append(sp_metadata.name)
126129

127130
@staticmethod
@@ -205,8 +208,7 @@ def test_start_auth_name_id_policy():
205208

206209
assert resp.status == "303 See Other", "Must be a redirect to the discovery server."
207210

208-
disco_resp = parse.parse_qs(resp.message.replace(
209-
TestConfiguration.get_instance().spconfig["disco_srv"] + "?", ""))
211+
disco_resp = parse_qs(urlparse(resp.message).query)
210212
sp_config = TestConfiguration.get_instance().spconfig["config"]
211213
sp_disco_resp = sp_config["service"]["sp"]["endpoints"]["discovery_response"][0][0]
212214
assert "return" in disco_resp and disco_resp["return"][0].startswith(sp_disco_resp), \
@@ -266,22 +268,41 @@ def auth_req_callback_func(context, internal_resp):
266268
resp = samlbackend.start_auth(context, internal_req)
267269
assert resp.status == "303 See Other", "Must be a redirect to the discovery server."
268270

269-
sp_disco_resp = spconfig["config"]["service"]["sp"]["endpoints"]["discovery_response"][0][0]
270-
disco_resp = parse.parse_qs(resp.message.replace(spconfig["disco_srv"] + "?", ""))
271-
info = parse.parse_qs(disco_resp["return"][0].replace(sp_disco_resp + "?", ""))
271+
disco_resp = parse_qs(urlparse(resp.message).query)
272+
273+
info = parse_qs(urlparse(disco_resp["return"][0]).query)
272274
info[samlbackend.idp_disco_query_param] = idpconfig["entityid"]
273275
context = Context()
274276
context.request = info
275277
context.state = state
276278
resp = samlbackend.disco_response(context)
277-
assert resp.status == "200 OK", "A post must be 200 OK."
278-
sp_url, req_params = fakeidp.get_post_action_body(resp.message)
279+
assert resp.status == "303 See Other"
280+
req_params = dict(parse_qsl(urlparse(resp.message).query))
279281
url, fake_idp_resp = fakeidp.handle_auth_req(
280282
req_params["SAMLRequest"],
281283
req_params["RelayState"],
282-
BINDING_HTTP_POST,
284+
BINDING_HTTP_REDIRECT,
283285
"testuser1")
284286
context = Context()
285287
context.request = fake_idp_resp
286288
context.state = state
287289
samlbackend.authn_response(context, BINDING_HTTP_POST)
290+
291+
292+
def test_redirect_to_idp_if_only_one_idp_in_metadata(monkeypatch):
293+
sp_config = TestConfiguration.get_instance().spconfig
294+
monkeypatch.delitem(sp_config, "disco_srv")
295+
monkeypatch.setitem(sp_config["config"]["metadata"], "local", [
296+
FileGenerator.get_instance().create_metadata(None, "idp_metadata").name])
297+
298+
samlbackend = SamlBackend(None, INTERNAL_ATTRIBUTES, sp_config)
299+
300+
state = State()
301+
state.add("test", "state")
302+
context = Context()
303+
context.state = state
304+
internal_req = InternalRequest(UserIdHashType.transient, None)
305+
resp = samlbackend.start_auth(context, internal_req)
306+
307+
assert resp.status == "303 See Other"
308+
assert resp.message.split("?")[0] == "http://test.tester.se/sso/redirect"

tests/satosa/frontends/test_saml2.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@
3333
'edupersontargetedid': {'saml': ['eduPersonTargetedID'], 'openid': ['sub'],
3434
'facebook': ['id']},
3535
'name': {'saml': ['cn'], 'openid': ['name'], 'facebook': ['name']},
36-
'address': {'openid': ['address->street_address'], 'saml': ['postaladdress']},
3736
'surname': {'saml': ['sn', 'surname'], 'openid': ['family_name'],
38-
'facebook': ['last_name']}}, 'separator': '->'}
37+
'facebook': ['last_name']}}}
3938

4039
IDP_CERT_FILE, IDP_KEY_FILE = FileGenerator.get_instance().generate_cert()
4140

0 commit comments

Comments
 (0)