Code Monkey home page Code Monkey logo

satosa's Introduction

SATOSA

PyPI

A configurable proxy for translating between different authentication protocols such as SAML2, OpenID Connect and OAuth2.

Table of Contents

Use cases

In this section a set of use cases for the proxy is presented.

SAML2<->SAML2

There are SAML2 service providers for example Box which is not able to handle multiple identity providers. For more information about how to set up, configure and run such a proxy instance please visit Single Service Provider<->Multiple Identity providers

If an identity provider can not communicate with service providers in for example a federation, they can convert requests and make the communication possible.

SAML2<->Social logins

This setup makes it possible to connect a SAML2 service provider to multiple social media identity providers such as Google and Facebook. The proxy makes it possible to mirror an identity provider by generating SAML2 metadata corresponding to that provider and create dynamic endpoints which are connected to a single identity provider.

For more information about how to set up, configure and run such a proxy instance please read SAML2<->Social logins

SAML2<->OIDC

The proxy is able to act as a proxy between a SAML2 service provider and a OpenID connect provider SAML2<->OIDC

Contact

If you have any questions regarding operations/deployment of SATOSA please use the satosa-users mailing list.

satosa's People

Contributors

bajnokk avatar c00kiemon5ter avatar claycooper avatar ctr49 avatar dallerbarn avatar gijutsu avatar hlflanagan avatar ioparaskev avatar jkakavas avatar johanlundberg avatar leifj avatar melanger avatar mrvanes avatar peppelinux avatar rebeckag avatar rhoerbe avatar robellegate avatar rohe avatar s-hal avatar saxtouri avatar sebulibah avatar sgomez avatar shaardie avatar simonevisconti avatar skanct avatar skoranda avatar thijskh avatar thomaswar avatar vladimir-mencl-eresearch avatar z38 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

satosa's Issues

SAML Frontend always return NameID with format persistent

Function

def hash_type_to_saml_name_id_format(hash_type):
    """
    Translate satosa format to pySAML2 name format

    :type hash_type: satosa.internal_data.UserIdHashType
    :rtype: str
    :param hash_type: satosa format
    :return: pySAML2 name format
    """
    if hash_type == UserIdHashType.transient.name:
        return NAMEID_FORMAT_TRANSIENT
    elif hash_type == UserIdHashType.persistent.name:
        return NAMEID_FORMAT_PERSISTENT
    return NAMEID_FORMAT_PERSISTENT

in https://github.com/SUNET/SATOSA/blob/master/src/satosa/frontends/saml2.py#L31

compares hash_type which is a UserIdHashType object to UserIdHashType.transient.name which is a string. This comparison is always False, hence the default return is always followed and the SAML2 frontent always creates an assertion with NameID format persistent in the Subject.

Docker image broken

I'd like to know how alive satosa is at the moment because The Docker image was built 4 months ago but when I try to run the image I get the following error:

/tmp/satosa/start.sh: line 30: make_satosa_saml_metadata.py: command not found

I'm surprised nobody has noticed?

I'm totally new to Docker, so I might have missed some obvious configuration or bootstrapping, but I'd expect the docs to fully cover the necessary work to run the image?

Unavailable attribute causes 'Unknown error'

If an attribute has been defined in the hash dictionary in the configuration and this attribute is not available for a given transaction, this causes SAtoSA to fail with an 'Unknown error'

The stacktrace is as follows:

[2017-04-28 07:48:24] [ERROR]: Unknown error
Traceback (most recent call last):
  File "/home/debian/vopaas/virtualenv/lib/python3.4/site-packages/satosa/base.py", line 255, in run
    resp = self._run_bound_endpoint(context, spec)
  File "/home/debian/vopaas/virtualenv/lib/python3.4/site-packages/satosa/base.py", line 203, in _run_bound_endpoint
    return spec(context)
  File "/home/debian/vopaas/virtualenv/lib/python3.4/site-packages/satosa/micro_services/consent.py", line 79, in _handle_consent_response
    return self._end_consent(context, internal_response)
  File "/home/debian/vopaas/virtualenv/lib/python3.4/site-packages/satosa/micro_services/consent.py", line 218, in _end_consent
    return super().process(context, internal_response)
  File "/home/debian/vopaas/virtualenv/lib/python3.4/site-packages/satosa/micro_services/base.py", line 33, in process
    return self.next(context, data)
  File "/home/debian/vopaas/virtualenv/lib/python3.4/site-packages/satosa/base.py", line 139, in _auth_resp_finish
    for v in internal_attributes[attribute]]
KeyError: 'edupersonprincipalname'

This happens because an assumption has been made that if a attribute is configured for hashing, it will always be available.

debug mdq support for saml_frontend (idp)

specifying metadata as an MDQ doesn't work for an IdP. Since metadata lookup comes after the discovery phase (when you have >1 IdP) there is no reason it shouldn't work.

id_token : iat the same as exp

Hi,
Scenario: oidc - frontend, saml - backend;
client receives always id_token where value of iat is the same as exp
sample decoded payload:
{ "sub": "e02c372f1a5f8df03265b68f7cdc2e22115eee7f39eb95938480e0c756f14b9f8732ca693f00471d19b80f67a8124b9a1dc587502143ec02daff3b943544a768", "iat": 1495527682.2663593, "aud": [ "7FTl3vGXxRpC" ], "exp": 1495531282.2663598, "at_hash": "LgBpOuidp-mVyGMwXTzM6A", "iss": "https://op-test.heanet.ie" }
In logs I always get that 'code' has already been used, whis is not true.

Sample exceptions I get:
Traceback (most recent call last): File "/opt/satosa/lib/python3.5/site-packages/satosa/frontends/openid_connect.py", line 322, in token_endpoint response = self.provider.handle_token_request(urlencode(context.request), headers) File "/opt/satosa/lib/python3.5/site-packages/pyop/provider.py", line 313, in handle_token_request return self._do_code_exchange(token_request, extra_id_token_claims) File "/opt/satosa/lib/python3.5/site-packages/pyop/provider.py", line 353, in _do_code_exchange access_token = self.authz_state.exchange_code_for_token(token_request['code']) File "/opt/satosa/lib/python3.5/site-packages/pyop/authz_state.py", line 159, in exchange_code_for_token raise InvalidAuthorizationCode('{} has already been used'.format(authorization_code)) pyop.exceptions.InvalidAuthorizationCode: a0556ec7d2974e6fbd1879de4000c540 has already been used [2017-05-23 09:07:26] [DEBUG]: [urn:uuid:70e586d6-05e6-4bb6-a5b9-eb4685ee630f] Saving state as cookie, secure: True, max-age: 1200, path: /

Fails if URL is hard-coded other than the actual destination

In src/frontends/saml2.py

In the method :
def _handle_authn_response(self, context, internal_response, idp):
Im customising the destination from
http_args = idp.apply_binding(resp_args["binding"], str(resp), resp_args["destination"],
request_state["relay_state"], response=True)
to
http_args = idp.apply_binding(resp_args["binding"], str(resp), 'https://public-ip-address:5050/',
request_state["relay_state"], response=True)
but this fails.

Any suggestions ?

missing entityID in metadata yields "unknown error"

2016-04-27 08:22:32,604 [5611] [ERROR] Unknown error
Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/satosa/base.py", line 274, in run
    resp = self._run_bound_endpoint(context, spec)
  File "/usr/local/lib/python3.4/dist-packages/satosa/base.py", line 202, in _run_bound_endpoint
    return spec[0](context, *spec[1:])
  File "/usr/local/lib/python3.4/dist-packages/satosa/frontends/saml2.py", line 70, in handle_authn_request
    return self._handle_authn_request(context, binding_in, self.idp)
  File "/usr/local/lib/python3.4/dist-packages/satosa/frontends/saml2.py", line 225, in _handle_authn_request
    context.state)
  File "/usr/local/lib/python3.4/dist-packages/satosa/frontends/saml2.py", line 171, in extract_request
    entity_id=_authn_req.issuer.text, request=_authn_req)
  File "/usr/local/lib/python3.4/dist-packages/saml2/entity.py", line 283, in pick_binding
    srvs = sfunc(entity_id, binding, descr_type)
  File "/usr/local/lib/python3.4/dist-packages/saml2/mdstore.py", line 1063, in assertion_consumer_service
    "assertion_consumer_service", binding)
  File "/usr/local/lib/python3.4/dist-packages/saml2/mdstore.py", line 952, in service
    raise UnknownSystemEntity(entity_id)
saml2.s_utils.UnknownSystemEntity: https://dev.play.sunet.se

This could definitely be improved upon :-)

Is the remote metadata example correct?

The metadata example for remote URL shows:

"metadata": {
"remote":
-url:https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral2&set=saml2,
-cert:null
}

However, pySAML (https://dirg.org.umu.se/static/pysaml2/howto/config.html#metadata) shows:
"metadata" : {
"local": [
"metadata.xml", "vo_metadata.xml"
],
"remote": [
{
"url":"https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral2&set=saml2",
"cert":"kalmar2.cert"
}],
},

Which could also be like so:
metadata:
remote:
- url:https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral2&set=saml2,
cert:null

But not as presented in the example?

Clean error reporting

If an exception is well understood and reported, there is no point in adding a stacktrace. E.g.: currently a saml2.s_utils.UnknownSystemEntity exception will result in a stacktrace (and disguise it as an "unknow error", btw). As the reason is a missing entry in metadata, a concise "configuration error: unknown system entity https://sp.example.org/sp" is suffient. Therefore I propose to add in base:run

        except UnknownSystemEntity as err:
            satosa_logging(logger, logging.ERROR,
                           "configuration error: unknown system entity " + str(err),
                           context.state, exc_info=False)
            raise

However, proxy_server:run will handle the raised exception as a general Exception and print the stack trace. A possible solution would be to define a generic SatosaAlreadyReportedException that will silentce the traceback by adding the second line in following snippet from proxy_server.

        except (Exception, SatosaAlreadyReportedException) as err:
            if type(err) != SatosaAlreadyReportedException:        
                logger.exception("%s" % err)
            if debug:
                raise
            resp = ServiceError("%s" % err)
            return resp(environ, start_response)

What do people think?

`UnboundLocalError: local variable 'attributes' referenced before assignment` in _filter_attributes (satosa/frontends/saml2.py)

Code Version

master (3.4.8)

Expected Behavior

The _filter_attributes function in satosa/frontends/saml2.py should return all attributes or some other sensible value if no IdP policy is configured, or it should signal a human-readable error directing the user to configure a suitable IdP policy.

Current Behavior

If no IdP policy is configured (or if it is configured incorrectly), the _filter_attributes function does not set a return value, which results in the following traceback:

[2018-03-06 23:52:06,102] [ERROR] [satosa.proxy_server]: Unknown error
Traceback (most recent call last):
  File "/opt/satosa/lib/python3.6/site-packages/satosa/base.py", line 268, in run
    resp = self._run_bound_endpoint(context, spec)
  File "/opt/satosa/lib/python3.6/site-packages/satosa/base.py", line 216, in _run_bound_endpoint
    return spec(context)
  File "/opt/satosa/lib/python3.6/site-packages/satosa/backends/saml2.py", line 235, in authn_response
    return self.auth_callback_func(context, self._translate_response(authn_response, context.state))
  File "/opt/satosa/lib/python3.6/site-packages/satosa/base.py", line 185, in _auth_resp_callback_func
    return self.response_micro_services[0].process(context, internal_response)
  File "/opt/satosa_microservices/src/satosa/micro_services/primary_identifier.py", line 203, in process
    return super().process(context, data)
  File "/opt/satosa/lib/python3.6/site-packages/satosa/micro_services/base.py", line 33, in process
    return self.next(context, data)
  File "/opt/satosa_microservices/src/satosa/micro_services/ldap_attribute_store.py", line 379, in process
    return super().process(context, data)
  File "/opt/satosa/lib/python3.6/site-packages/satosa/micro_services/base.py", line 33, in process
    return self.next(context, data)
  File "/opt/satosa/lib/python3.6/site-packages/satosa/base.py", line 159, in _auth_resp_finish
    return frontend.handle_authn_response(context, internal_response)
  File "/opt/satosa/lib/python3.6/site-packages/satosa/frontends/saml2.py", line 89, in handle_authn_response
    return self._handle_authn_response(context, internal_response, self.idp)
  File "/opt/satosa/lib/python3.6/site-packages/satosa/frontends/saml2.py", line 282, in _handle_authn_response
    idp, internal_response, context)
  File "/opt/satosa/lib/python3.6/site-packages/satosa/frontends/saml2.py", line 262, in _filter_attributes
    return attributes
UnboundLocalError: local variable 'attributes' referenced before assignment

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/satosa/lib/python3.6/site-packages/satosa/proxy_server.py", line 113, in __call__
    resp = self.run(context)
  File "/opt/satosa/lib/python3.6/site-packages/satosa/base.py", line 284, in run
    raise SATOSAUnknownError("Unknown error") from err
satosa.exception.SATOSAUnknownError: Unknown error

Possible Solution

Return a better error message/exception, or set a sensible default return value (e.g., the unfiltered list of attributes).

Steps to Reproduce

  1. Deploy SATOSA using mod_wsgi.
  2. Enable the SAML2 front end but omit the config:idp_config:service:idp:policy key from the configuration.
  3. Attempt SAML web SSO through the proxy and note the error.

Generate user identifiers from Persistent Name IDs

I'm having trouble getting started with the SAML backend. Whenever I try to login an exception gets thrown:

[2016-10-18 15:00:37] [DEBUG]: [urn:uuid:e9b38285-e2a5-43e5-b11a-8aee973a597c] received attributes:
{
    "displayName": [
        "John Doe"
    ],
    "eduPersonScopedAffiliation": [
        "member"
    ],
    "eduPersonTargetedID": [
        {
            "NameID": {
                "name_qualifier": "https://idp.local/idp/sso",
                "format": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
                "sp_name_qualifier": "https://satosa.local/example/proxy_saml2_backend.xml",
                "value": "KHj2iBGk+sAhaQw+lIVaxCdfJFw="
            }
        }
    ],
    "mail": [
        "[email protected]"
    ]
}
[2016-10-18 15:00:37] [ERROR]: [urn:uuid:e9b38285-e2a5-43e5-b11a-8aee973a597c] Uncaught exception
Traceback (most recent call last):
  File "/opt/satosa/src/satosa/base.py", line 256, in run
    resp = self._run_bound_endpoint(context, spec)
  File "/opt/satosa/src/satosa/base.py", line 204, in _run_bound_endpoint
    return spec(context)
  File "/opt/satosa/src/satosa/backends/saml2.py", line 162, in authn_response
    return self.auth_callback_func(context, self._translate_response(authn_response, context.state))
  File "/opt/satosa/src/satosa/base.py", line 165, in _auth_resp_callback_func
    self.config["INTERNAL_ATTRIBUTES"]["user_id_from_attrs"]]
  File "/opt/satosa/src/satosa/base.py", line 164, in <listcomp>
    user_id = ["".join(internal_response.attributes[attr]) for attr in
TypeError: sequence item 0: expected str instance, dict found
[2016-10-18 15:00:37] [ERROR]: Unknown error
Traceback (most recent call last):
  File "/opt/satosa/src/satosa/base.py", line 256, in run
    resp = self._run_bound_endpoint(context, spec)
  File "/opt/satosa/src/satosa/base.py", line 204, in _run_bound_endpoint
    return spec(context)
  File "/opt/satosa/src/satosa/backends/saml2.py", line 162, in authn_response
    return self.auth_callback_func(context, self._translate_response(authn_response, context.state))
  File "/opt/satosa/src/satosa/base.py", line 165, in _auth_resp_callback_func
    self.config["INTERNAL_ATTRIBUTES"]["user_id_from_attrs"]]
  File "/opt/satosa/src/satosa/base.py", line 164, in <listcomp>
    user_id = ["".join(internal_response.attributes[attr]) for attr in
TypeError: sequence item 0: expected str instance, dict found

internal_attributes.yml

attributes:
  displayname:
    openid: [nickname]
    saml: [displayName]
  edupersontargetedid:
    facebook: [id]
    openid: [sub]
    saml: [eduPersonTargetedID]
  mail:
    facebook: [email]
    openid: [email]
    saml: [email, emailAdress, mail]
hash: [edupersontargetedid]
user_id_from_attrs: [edupersontargetedid]
user_id_to_attr: edupersontargetedid

Is there a way I can still use eduPersonTargetedID?

openid_connect frontend can't read clients from static file

pyOP supports reading client information from a json file but the openid_connect frontend doesn't allow for this. It only supports mongo_db or in memory dynamic client registration.

@mrvanes captured that in #144 , but I got mixed up and answered based on a combination of satosa and specific InAcademia setup.

We don't need the FileWrapper from @mrvanes PR, but the change in https://github.com/SUNET/SATOSA/pull/144/files#diff-e79c7f4af2d2a06a1b59f5b15331cffcR122 is relevant so I will make a new PR based on that

Multiple code changes available, need priority/interest feedback

I've been hacking around in SATOSA for SURFnet PoC implementation and I've had to create some changes to cater for our specific needs/tests. As maintaining a fork poses some effort we would like to minimize, it would be nice if some, preferably all, changes were incorporated upstream. As cherrypicking the changes is somewhat cumbersome I'd like to know what changes would be valued highest or welcome at all (see PR#161)

microservices

easy to make pull-request as they're isolated

  • Custom Alias file serving microservice (to service metadata and static error/info pages). Used by next microservice for example.
  • DB ACL microservice (COManage CO membership specific ACL microservice)
  • DB Attribute store (COmanage CO membership specific attribute aggregation microservice)

changes

often more changes on multiple places in the code, need cherry picking

  • Map outgoing attributes to all incoming aliases instead of only first
  • SAML Mirrored Backend, to create full mesh-like federation with hub-and-spoke proxy.
  • Symmetric transparent metadata creation, see above
  • Backend specific OIDC frontend endpoints
  • SAML frontend, pass all attributes if filter empty, to work around unwanted attribute format filtering.
  • Consent, pass all attributes if filter empty, see above

IE11 STATE_ENCRYPTION_KEY decode error

Sign on to test.ucom.gv.at failing with "ValueError: Error 65537 while instatiating the CBC mode" when calling _load_state() in satosa.base. (Being then generalized into satosa.exception.SATOSAUnknownError)

I observed that IE11 includes and empty STATE_ENCRYPTION_KEY cookie , causing the decrypt code in cookie_to_state() to fail with an exception that is not catched in _load_state.

...
return CbcMode(cipher_state, iv)
File "/opt/satosa/lib/python3.5/site-packages/Cryptodome/Cipher/_mode_cbc.py", line 101, in init
% result)
ValueError: Error 65537 while instatiating the CBC mode

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/opt/satosa/lib/python3.5/site-packages/satosa/proxy_server.py", line 113, in call
resp = self.run(context)
File "/opt/satosa/lib/python3.5/site-packages/satosa/base.py", line 277, in run
raise SATOSAUnknownError("Unknown error") from err
satosa.exception.SATOSAUnknownError: Unknown error

SAML frontend loads metadata on every request

With SaToSa SAML frontend configured with edugain metadata, every request takes several minutes to serve. It seems like the plugin is parsing the metadata on every request, because the delay is not noticable when running with smaller metadata and the gunicorn processes do almost nothing but memory operations (according to strace). Enabling or disabling signature checking doesn't change the request time considerably.

When the service is started, all workers (3) behave similarly: high CPU usage for a couple of minutes. This would be acceptable if the subsequent incoming requests would be served fast, but this is not the case.

If it is a configuration issue, please give a hint where to look at metadata caching options. Please let me know if you need any more information. I'm running version 3.4.2.

put secrets in separate files

Config data and secrets (such as proxy_conf/STATE_ENCRYPTION_KEY) should go into separate files. Rationale: Deployment environments (e.g. Openshift) pull the configuration from some external repository but inject secrets locally.

docs/README.md errors

It seems the Docker image is not the preferred installation route anymore and this should be reflected in the docs. Also, -h is not a valid option for satosa-saml-metadata, it is --help.
Third: on Ubuntu 16.10, python 2.7 is the default python interpreter and causes some awkward python versioning entanglement. A solid, working python3 environment can be built using:

# apt install python3 python3-setuptools virtualenv python3-pip
# virtualenv -p /usr/bin/python3 py3env
# source py3env/bin/activate
(py3env) # pip install satosa

Reauthenticating at saml frontend alternates between error and success

When I clear my authenticated session at test SP and request new authentication, satosa proxy fails on Saml2/sso/post:

[2017-03-23 14:00:01] [DEBUG]: [urn:uuid:1360174e-a648-4647-aec5-db0d027f206c] Routing path: Saml2/sso/post
[2017-03-23 14:00:01] [DEBUG]: [urn:uuid:1360174e-a648-4647-aec5-db0d027f206c] Found registered endpoint: module name:'Saml2IDP', endpoint: Saml2/sso/post
[2017-03-23 14:00:01] [ERROR]: [urn:uuid:1360174e-a648-4647-aec5-db0d027f206c] Uncaught exception
Traceback (most recent call last):
  File "/opt/satosa/py3env/lib/python3.5/site-packages/satosa/base.py", line 255, in run
    resp = self._run_bound_endpoint(context, spec)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/satosa/base.py", line 203, in _run_bound_endpoint
    return spec(context)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/satosa/frontends/saml2.py", line 96, in handle_authn_request
    return self._handle_authn_request(context, binding_in, self.idp)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/satosa/frontends/saml2.py", line 177, in _handle_authn_request
    req_info = idp.parse_authn_request(context.request["SAMLRequest"], binding_in)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/saml2/server.py", line 235, in parse_authn_request
    "single_sign_on_service", binding)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/saml2/entity.py", line 854, in _parse_request
    must=must, only_valid_cert=only_valid_cert)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/saml2/request.py", line 96, in loads
    only_valid_cert=only_valid_cert)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/saml2/request.py", line 59, in _loads
    raise IncorrectlySigned()
saml2.response.IncorrectlySigned
[2017-03-23 14:00:01] [ERROR]: Unknown error
Traceback (most recent call last):
  File "/opt/satosa/py3env/lib/python3.5/site-packages/satosa/base.py", line 255, in run
    resp = self._run_bound_endpoint(context, spec)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/satosa/base.py", line 203, in _run_bound_endpoint
    return spec(context)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/satosa/frontends/saml2.py", line 96, in handle_authn_request
    return self._handle_authn_request(context, binding_in, self.idp)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/satosa/frontends/saml2.py", line 177, in _handle_authn_request
    req_info = idp.parse_authn_request(context.request["SAMLRequest"], binding_in)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/saml2/server.py", line 235, in parse_authn_request
    "single_sign_on_service", binding)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/saml2/entity.py", line 854, in _parse_request
    must=must, only_valid_cert=only_valid_cert)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/saml2/request.py", line 96, in loads
    only_valid_cert=only_valid_cert)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/saml2/request.py", line 59, in _loads
    raise IncorrectlySigned()
saml2.response.IncorrectlySigned

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/satosa/py3env/lib/python3.5/site-packages/satosa/proxy_server.py", line 112, in __call__
    resp = self.run(context)
  File "/opt/satosa/py3env/lib/python3.5/site-packages/satosa/base.py", line 266, in run
    raise SATOSAUnknownError("Unknown error") from err
satosa.exception.SATOSAUnknownError: Unknown error

Attempting the authentication immediately after, results in a successful authentication. The next authentication fails again etc. etc.

BASE must not include a path in mod_wsgi-hosted deployments

Code Version

master (v3.4.8)

Expected Behavior

I should be able to host SATOSA at any valid URL path, e.g., setting BASE to https://federation.example.com/satosa.

Likewise, the following values of BASE should be treated the same: https://federation.example.com/ and https://federation.example.com. However, only the latter value of BASE results in a working configuration.

Current Behavior

If one hosts the SATOSA WSGI application at a path other than /, and if one sets BASE in the SATOSA proxy configuration file to something other than <scheme>://<host>, then the SAML back end registers invalid endpoint mappings, e.g. with BASE set to https://federation.example.com/satosa, it sets up these mappings (url_map):

[
  ('^satosa/Saml2/acs/post$', 
   functools.partial(<bound method SAMLBackend.authn_response of <satosa.backends.saml2.SAMLBackend object at 0x7fcfc24a61d0>>, 
   binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST')), 
  ('^satosa/Saml2/acs/redirect$', 
   functools.partial(<bound method SAMLBackend.authn_response of <satosa.backends.saml2.SAMLBackend object at 0x7fcfc24a61d0>>, 
   binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'))
]

This results in the following error:

Unable to determine the entityID's for the IdP or SP

Whereas with BASE set to https://federation.example.com, it sets up these mappings

[
  ('^/Saml2/acs/post$', 
   functools.partial(<bound method SAMLBackend.authn_response of <satosa.backends.saml2.SAMLBackend object at 0x7f89c4aff1d0>>, 
   binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST')), 
  ('^/Saml2/acs/redirect$', 
   functools.partial(<bound method SAMLBackend.authn_response of <satosa.backends.saml2.SAMLBackend object at 0x7f89c4aff1d0>>, 
   binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'))
]

Due to differences in how the SAML front end configures endpoint mappings, it works as expected for both values of BASE.

Possible Solution

This might be related to issue #148.

As a workaround for situations where one might wish to co-locate SATOSA and other web applications or content on the same virtual host, use the WSGIScriptAliasMatch directive with a negative lookahead; for example:

WSGIScriptAliasMatch ^/(?!(Shibboleth\.sso|registry|img|css|js|favicon.ico|error.html)) /usr/lib/python3.6/site-packages/satosa/wsgi.py

Steps to Reproduce

  1. Deploy SATOSA using mod_wsgi.
  2. Use WSGIScriptAlias /satosa ... instead of WSGIScriptAlias / ....
  3. Set BASE in proxy_conf.yaml to <scheme>://<host>/satosa.
  4. Log into a SAML SP behind SATOSA; note the error when a SAML IdP posts a SAML authentication response to SATOSA's ACS endpoint.

Inconsistent use of base_url throughout the code

I tried to map SATOSA to a URI'd path behind a reverse proxy and didn't succeed. Looking through the code there are many mixes of the use of BASE (self.base_url) that defeat using it properly.

  1. metadata (generation) uses it
  2. register_endpoints of saml front and backend modules don't use it, but oidc frontend does
  3. discovery return_url doesn't use it
  4. saml2 backend ACS doesn't

This is where I stopped debugging and fixing the code.

All the above problems can be overcome seperately by wisely choosing a combination of reverse proxy conf (include base path in backend request or not) and SATOSA conf (with or without base path), but never together as as working system. It's a classical waterbed.

This issue is here only to address the problem, because we decided to go vhost based reverse proxy to keep the project going.

To clarify what I mean with base path URI'd SATOSA:
reverse proxy address: https:///satosa/
backend server: http://localhost:8080/ or http://localhost:8080/satosa

explicit relay of proxy errors to the frontend

Durch the setup of a rocket chat server fronted by satosa (SAML2SAML) I encountered various configurations errors, like a certificate problem with the metadata, clock drag and incorrect metadata registration. However, the error messagefron the frontend is always "Authentication failed. Error id ....".

I think that - at least for QA systems - error messages should include the root cause. "Authentication failed may be also misleading when the error is not in the actual authentication process.

Frontend metadata should not include target contact info

reported by @surfnet-niels:
When frontend metadata is generated for the entities connected to the back, for the SAML entities it contact data (technical/support/admin) is being copied over from the backend metadata.
This does not make sense, as the remote contacts are not/ should not be aware of the fact we run in a proxy in front of their systems. We should get the queries from other entities, and if need be we will contact the backend entities.
Therefor, our foreend metadata should only contain our contact data.

Docs are missing discovery API explanation

I found the answer in the code, but would have preferred to find it in the docs ;)

In short, for those looking for an answer: Discovery service should return to url in return parameter and return param entityID for the chosen entityID.

On a sidenote: in order to shortcut the discovery service in test environment I pointed the discovery service URL back to the disco_response endpoint (/Saml2/disco in example) containing a preselected entityID. However, the create_discovery_service_request itself adds an entityID param as well, so there is some contamination that could have been prevented by choosing another consumer parameter for return entityID. I solved it by returning and checking for eID. Also, pysaml2 has a bug for discovery service url's containing a querypart, which I already created here IdentityPython/pysaml2#402

Reading config fails if no microservcies are configured

# Read plugin configs from dict or file path

If no microservcies are configured in proxy.yaml, SaToSa will not start nor construct SAML metadata as the above module fails to load plugin configuration:

File \"/home/debian/vopaas/virtualenv/lib/python3.5/site-packages/satosa/scripts/satosa_saml_metadata.py\", line 43, in create_and_write_saml_metadata, 
    satosa_config = SATOSAConfig(proxy_conf), 
File \"/home/debian/vopaas/virtualenv/lib/python3.5/site-packages/satosa/satosa_config.py\", line 50, in __init__, 
    for config in self._config.get(key, []):, 
TypeError: 'NoneType' object is not iterable"], "stdout": "", "stdout_lines": []

satosa-saml-metadata chokes on cert pem file containing trailing newline in signing cert.

While copying certificates around I accidentally created a (signing) certificate file that had a trailing newline after the -----END CERTIFICATE----- line and satosa-saml-metadata choked on validate_base64 for this cert: binascii.Error: Incorrect padding. It turns out the base64 value contains the -----END CERTIFICATE----- part of the cert (I added debug code to validate_base64 to show val).

I tried fixing this by adding a .strip() to the read_file command in read_cert_from_file in sigver.py @734 but this didn't resolve the problem?

So, I'm glad I found the problem and was able to fix the cert, but I was not able to make read_cert_from_file a bit more resilient for end-user mistakes like this?

don't barf on /favicon.ico

When pointing a browser at the proxy saml backend metadata (from docker image) I get this:

2016-04-22 09:51:13,719 [108] [ERROR] Unknown error
Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/satosa/base.py", line 273, in run
    spec = self.module_router.endpoint_routing(context)
  File "/usr/local/lib/python3.4/dist-packages/satosa/routing.py", line 155, in endpoint_routing
    for regex, spec in self.backends[backend]["endpoints"]:
KeyError: 'favicon.ico'

Very likely this is a non-fatal error but it should be avoided. Serve up a simple favicon or return a 404 - whatever makes most browsers happy.

No Format in NameIDPolicy causes use of transient always with SAML frontend

It is acceptable SAML for an to include a element that has the AllowCreate attribute but not the Format attribute. When the SAML frontend receives such a request it should consult the SP metadata to determine which NameID format to use. Instead if the Format attribute is not present the request format in the SP metadata is ignored and transient is always used.

SALTs should not be allowed to be empty when starting SATOSA

SATOSA supports SALTing in various places, which is good. However if SALTs end up empty (neither being set via proxy config or env variable) this does not yield a WARN (or maybe even a full stop).
Not SALTing is probably not a good idea from a security point of view

Add requested ACS URL to log message

Please add the actual requested ACS URL from the SAML2 authn request to the log message that is generated when the requested ACS URL is not found in metadata.

This message should include the requested URL that was not found (the one listed below is the entityID):
[2017-07-06 17:13:47] [ERROR]: Failed to find consumer URL: https://confluence.testbed.tier.internet2.edu/shibboleth, ['urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'], spsso

This would make troubleshooting considerably easier.

Thanks!

OIDC frontend db_uri not optional

Despite the comment in example/frontends/openid_connect_frontend.yaml.example:

db_uri: mongodb://db.example.com # optional: only support MongoDB, will default to in-memory storage if not specified

SATOSA won't load the oidc frontend w/o db_uri containing a mongodb URI

make_satosa_saml_metadata.py fails with hardcoded metadata location

When configuring a new saml2 frontend using the template provided (saml2_frontend.yaml.example) generating metadata fails if the metadata location is not defined

metadata:
local: [metadata/idp.xml]

Traceback (most recent call last):
File "/home/ubuntu/vopaas/virtualenv/bin/make_satosa_saml_metadata.py", line 328, in
make_satosa_metadata(option)
File "/home/ubuntu/vopaas/virtualenv/bin/make_satosa_saml_metadata.py", line 168, in make_satosa_metadata
backend_modules = _load_endpoint_modules(backend_plugins, None, conf_mod.INTERNAL_ATTRIBUTES)
File "/home/ubuntu/vopaas/virtualenv/lib/python3.5/site-packages/satosa/plugin_loader.py", line 170, in _load_endpoint_modules
module_inst = plugin.module(callback, internal_attributes, plugin.config)
File "/home/ubuntu/vopaas/virtualenv/lib/python3.5/site-packages/satosa/backends/saml2.py", line 68, in init
sp_config = SPConfig().load(copy.deepcopy(config["config"]), False)
File "/home/ubuntu/vopaas/virtualenv/lib/python3.5/site-packages/saml2/config.py", line 350, in load
self.load_complex(cnf, metadata_construction=metadata_construction)
File "/home/ubuntu/vopaas/virtualenv/lib/python3.5/site-packages/saml2/config.py", line 290, in load_complex
self.load_metadata(cnf["metadata"]))
File "/home/ubuntu/vopaas/virtualenv/lib/python3.5/site-packages/saml2/config.py", line 394, in load_metadata
mds.imp(metadata_conf)
File "/home/ubuntu/vopaas/virtualenv/lib/python3.5/site-packages/saml2/mdstore.py", line 885, in imp
self.load(key, val)
File "/home/ubuntu/vopaas/virtualenv/lib/python3.5/site-packages/saml2/mdstore.py", line 871, in load
_md.load()
File "/home/ubuntu/vopaas/virtualenv/lib/python3.5/site-packages/saml2/mdstore.py", line 638, in load
_txt = self.get_metadata_content()
File "/home/ubuntu/vopaas/virtualenv/lib/python3.5/site-packages/saml2/mdstore.py", line 635, in get_metadata_content
return open(self.filename, 'rb').read()
FileNotFoundError: [Errno 2] No such file or directory: 'metadata/idp.xml'

According to https://github.com/its-dirg/SATOSA/blob/master/doc/README.md#saml_plugin this file should list all SAML entities the proxy will engage with. Though I understand a none existing file is an issue, I do not understand why make_satosa_saml_metadata.py should fail if the proxy has no entities. It should not need to know about remote entities for generating its own metadata?
In addition, it is not clear whete the file should be located.
Finally, if it should contains both IdP and SP metadata, would a filename like "remote_entities" or something not make more sence?

proxy_server incorrectly assumes bare POST CONTENT_TYPE

proxy_server.py assumes a bare CONTENT_TYPE of application/x-www-form-urlencoded or application/json to correctly unpack POST data. My test applicatoin (Chrome Postman extension) sends POST requests with CONTENT_TYPE: application/x-www-form-urlencoded; charset=UTF-8, wich will fail the test at line 39. The correct way to check would be:

if "application/x-www-form-urlencoded" in environ["CONTENT_TYPE"]:

and at line 41:

elif "application/json" in environ["CONTENT_TYPE"]:

I can now correctly use the built-in oAuth 2.0 auth flow in Postman.

Multi-value attributes i OIDC->SAML

If we have a OpenId frontend and a SAML backend where the IDP returns several attributes with the same name, then SATOSA will only be able to map the first attribute to a single claim value. It should map the attributes to a claim with an array of values.

The problem in the code are: satosa/frontends/openid_connect.py
self.user_db[internal_resp.user_id] = {k: v[0] for k, v in attributes.items()}

Can internal response attributes have emptyvalues?

Hi,

I've come across a setup/configuration where we have internal_response attributes which value is an empty list. Something like :

{'edupersonorcid': [],
 'eppn': ['[email protected]'],
 'surname': ['Kakavas']}

The attributes get their value from the ldap_attribute_store microservice (in this example edupersonorcid has no values in LDAP ) and the frontend that breaks because of this is the openid_connect plugin, specifically https://github.com/SUNET/SATOSA/blob/d20500117c22f891ca44f7808a1ed6fab70738d7/src/satosa/frontends/openid_connect.py#L118

which raises IndexError: list index out of range as expected.

So the question is :

  • Do we make sure that we don't end up with empty lists in our internal_attributes ( i..e. fix this in the ldap attribute microservice ) or
  • Do we make sure our frontends are able to handle this ? I'd guess that the saml2 frontend is already more lenient as I know @skoranda has been using the ldap_attribute_store microservice in a saml/saml setup for some time now.

frontends.openid_connect._create_provider needs token_endpoint to silence Provider constructor

When "code" is enabled as response_types_supported in OpenIDConnectFrontend configuration, Provider refuses to instantiate due to missing required token_endpoint. This endpoint will be added later in code where response_types_supported is evaluated (#171) but then it's too late. Adding the following line in frontend/openid_connect.py@74 works around the exception.

            "token_endpoint": True

It's a quick'n'dirty fix but silences the Provider constructor, while eventually creating a correct token_endpoint after completing register_endpoints() anyway.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.