Beispiel #1
0
def echo_attributes(request,
                    config_loader_path=None,
                    template='djangosaml2/echo_attributes.html'):
    """Example view that echo the SAML attributes of an user"""
    state = StateCache(request.session)
    conf = get_config(config_loader_path, request)

    client = Saml2Client(conf,
                         state_cache=state,
                         identity_cache=IdentityCache(request.session))
    subject_id = _get_subject_id(request.session)
    identity = client.users.get_identity(subject_id,
                                         check_not_on_or_after=False)
    return render(request, template, {'attributes': identity[0]})
Beispiel #2
0
def logout_service(request, config_loader_path=None, next_page=None):
    """SAML Logout Response endpoint

    The IdP will send the logout response to this view,
    which will process it with pysaml2 help and log the user
    out.
    Note that the IdP can request a logout even when
    we didn't initiate the process as a single logout
    request started by another SP.
    """
    logger.debug('Logout service started')
    conf = get_config(config_loader_path, request)

    state = StateCache(request.session)
    client = Saml2Client(conf,
                         state_cache=state,
                         identity_cache=IdentityCache(request.session),
                         logger=logger)

    if 'SAMLResponse' in request.GET:  # we started the logout
        logger.debug('Receiving a logout response from the IdP')
        response = client.logout_response(request.GET['SAMLResponse'],
                                          binding=BINDING_HTTP_REDIRECT)
        state.sync()
        if response and response[1] == '200 Ok':
            return django_logout(request, next_page=next_page)
        else:
            logger.error('Unknown error during the logout')
            return HttpResponse('Error during logout')

    elif 'SAMLRequest' in request.GET:  # logout started by the IdP
        logger.debug('Receiving a logout request from the IdP')
        subject_id = _get_subject_id(request.session)
        response, success = client.logout_request(request.GET, subject_id)
        state.sync()
        if success:
            auth.logout(request)
            assert response[0][0] == 'Location'
            url = response[0][1]
            return HttpResponseRedirect(url)
        elif response is not None:
            assert response[0][0] == 'Location'
            url = response[0][1]
            return HttpResponseRedirect(url)
        else:
            logger.error('Unknown error during the logout')
            return HttpResponse('Error during logout')
    else:
        logger.error('No SAMLResponse or SAMLRequest parameter found')
        raise Http404('No SAMLResponse or SAMLRequest parameter found')
Beispiel #3
0
def logout():
    """
    SAML Logout Request initiator.
    This view initiates the SAML2 Logout request
    using the pysaml2 library to create the LogoutRequest.
    """
    # check csrf
    csrf = request.form['csrf']
    if csrf != session.get('_csrft_', None):
        abort(400)

    eppn = session.get('user_eppn')
    user = current_app.central_userdb.get_user_by_eppn(eppn)

    logger.debug('Logout process started for user {!r}'.format(user))
    state = StateCache(session)
    identity = IdentityCache(session)

    client = Saml2Client(current_app.saml2_config,
                         state_cache=state,
                         identity_cache=identity)

    subject_id = _get_name_id(session)
    if subject_id is None:
        logger.warning(
            'The session does not contain '
            'the subject id for user {!r}'.format(user))
        location = current_app.config.get('SAML2_LOGOUT_REDIRECT_URL')

    else:
        logouts = client.global_logout(subject_id)
        loresponse = logouts.values()[0]
        # loresponse is a dict for REDIRECT binding, and LogoutResponse for SOAP binding
        if isinstance(loresponse, LogoutResponse):
            if loresponse.status_ok():
                logger.debug('Performing local logout for {!r}'.format(user))
                session.clear()
                location = current_app.config.get('SAML2_LOGOUT_REDIRECT_URL')
                location = request.form.get('RelayState', location)
                return redirect(location)
            else:
                abort(500)
        headers_tuple = loresponse[1]['headers']
        location = headers_tuple[0][1]
        logger.info('Redirecting to {!r} to continue the logout process '
                    'for user {!r}'.format(location, user))

    state.sync()
    return redirect(location)
Beispiel #4
0
    def saml_client_for(self, idp_name=None):
        '''
        Given the name of an IdP, return a configuation.
        The configuration is a hash for use by saml2.config.Config
        '''

        if idp_name not in self.metadata_url_for and idp_name not in self.metadata:
            raise Exception("Settings for IDP '{}' not found".format(idp_name))
        acs_url = self.acs_format % idp_name
        https_acs_url = self.https_acs_format % idp_name

        if self.metadata_url_for:
            rv = requests.get(self.metadata_url_for[idp_name])
            metadata = rv.text
        else:
            metadata = self.metadata[idp_name]

        settings = {
            'entityid': 'iris',
            'metadata': {
                'inline': [metadata],
            },
            'service': {
                'sp': {
                    'endpoints': {
                        'assertion_consumer_service': [
                            (acs_url, BINDING_HTTP_REDIRECT),
                            (acs_url, BINDING_HTTP_POST),
                            (https_acs_url, BINDING_HTTP_REDIRECT),
                            (https_acs_url, BINDING_HTTP_POST)
                        ],
                    },
                    # Don't verify that the incoming requests originate from us via
                    # the built-in cache for authn request ids in pysaml2
                    'allow_unsolicited': True,
                    # Don't sign authn requests, since signed requests only make
                    # sense in a situation where you control both the SP and IdP
                    'authn_requests_signed': False,
                    'logout_requests_signed': True,
                    'want_assertions_signed': True,
                    'want_response_signed': True,
                },
            },
        }
        spConfig = Saml2Config()
        spConfig.load(settings)
        spConfig.allow_unknown_attributes = True
        saml_client = Saml2Client(config=spConfig)
        return saml_client
Beispiel #5
0
def idp_initiated(idp_name):
    logging.warning("idp_name")
    logging.warning(idp_name)

    settings = idp_settings[idp_name]
    settings['service'] = {
        'sp': {
            'endpoints': {
                'assertion_consumer_service':
                [(request.url, BINDING_HTTP_REDIRECT),
                 (request.url, BINDING_HTTP_POST)],
            },
            # Don't verify that the incoming requests originate from us via
            # the built-in cache for authn request ids in pysaml2
            'allow_unsolicited': True,
            'authn_requests_signed': False,
            'logout_requests_signed': True,
            'want_assertions_signed': True,
            'want_response_signed': False,
        },
    }
    logging.warning(settings)
    spConfig = Saml2Config()
    spConfig.load(settings)
    spConfig.allow_unknown_attributes = True

    cli = Saml2Client(config=spConfig)
    try:
        authn_response = cli.parse_authn_request_response(
            request.form['SAMLResponse'], entity.BINDING_HTTP_POST)
        authn_response.get_identity()
        user_info = authn_response.get_subject()
        username = user_info.text
        valid = True
    except Exception as e:
        logging.error(e)
        valid = False
        return str(e), 401

    # "JIT provisioning"
    if username not in user_store:
        user_store[username] = {
            'first_name': authn_response.ava['FirstName'][0],
            'last_name': authn_response.ava['LastName'][0],
        }
    user = User(username)
    login_user(user)
    # TODO: If it exists, redirect to request.form['RelayState']
    return redirect(url_for('user'))
Beispiel #6
0
def do_logout_service(request,
                      data,
                      binding,
                      config_loader_path=None,
                      next_page=None,
                      logout_error_template='djangosaml2/logout_error.html'):
    """SAML Logout Response endpoint

    The IdP will send the logout response to this view,
    which will process it with pysaml2 help and log the user
    out.
    Note that the IdP can request a logout even when
    we didn't initiate the process as a single logout
    request started by another SP.
    """
    logger.debug('Logout service started')
    conf = get_config(config_loader_path, request)

    state = StateCache(request.session)
    client = Saml2Client(conf,
                         state_cache=state,
                         identity_cache=IdentityCache(request.session))

    if 'SAMLResponse' in data:  # we started the logout
        logger.debug('Receiving a logout response from the IdP')
        response = client.parse_logout_request_response(
            data['SAMLResponse'], binding)
        state.sync()
        return finish_logout(request, response, next_page=next_page)

    elif 'SAMLRequest' in data:  # logout started by the IdP
        logger.debug('Receiving a logout request from the IdP')
        subject_id = _get_subject_id(request.session)
        if subject_id is None:
            logger.warning(
                'The session does not contain the subject id for user %s. Performing local logout'
                % request.user)
            auth.logout(request)
            return render_to_response(logout_error_template, {},
                                      context_instance=RequestContext(request))
        else:
            http_info = client.handle_logout_request(data['SAMLRequest'],
                                                     subject_id, binding)
            state.sync()
            auth.logout(request)
            return HttpResponseRedirect(get_location(http_info))
    else:
        logger.error('No SAMLResponse or SAMLRequest parameter found')
        raise Http404('No SAMLResponse or SAMLRequest parameter found')
Beispiel #7
0
def saml_client_for(idp_name=None):
    '''
    Given the name of an IdP, return a configuation.
    The configuration is a hash for use by saml2.config.Config
    '''

    if idp_name not in metadata_url_for:
        raise Exception("Settings for IDP '{}' not found".format(idp_name))
    acs_url = url_for("idp_initiated", idp_name=idp_name, _external=True)
    https_acs_url = url_for("idp_initiated",
                            idp_name=idp_name,
                            _external=True,
                            _scheme='https')

    #   SAML metadata changes very rarely. On a production system,
    #   this data should be cached as approprate for your production system.
    rv = requests.get(metadata_url_for[idp_name])

    settings = {
        'metadata': {
            'inline': [rv.text],
        },
        'service': {
            'sp': {
                'endpoints': {
                    'assertion_consumer_service':
                    [(acs_url, BINDING_HTTP_REDIRECT),
                     (acs_url, BINDING_HTTP_POST),
                     (https_acs_url, BINDING_HTTP_REDIRECT),
                     (https_acs_url, BINDING_HTTP_POST)],
                },
                # Don't verify that the incoming requests originate from us via
                # the built-in cache for authn request ids in pysaml2
                'allow_unsolicited': True,
                # Don't sign authn requests, since signed requests only make
                # sense in a situation where you control both the SP and IdP
                'authn_requests_signed': False,
                'logout_requests_signed': True,
                'want_assertions_signed': True,
                'want_response_signed': False,
            },
        },
    }
    spConfig = Saml2Config()
    spConfig.load(settings)
    spConfig.allow_unknown_attributes = True
    saml_client = Saml2Client(config=spConfig)
    return saml_client
Beispiel #8
0
def logout(request, config_loader_path=None):
    """SAML Logout Request initiator

    This view initiates the SAML2 Logout request
    using the pysaml2 library to create the LogoutRequest.
    """
    logger.debug('Logout process started')
    state = StateCache(request.session)
    conf = get_config(config_loader_path, request)

    client = Saml2Client(conf, state_cache=state,
                         identity_cache=IdentityCache(request.session))
    subject_id = _get_subject_id(request.session)
    if subject_id is None:
        logger.warning(
            'The session does not contains the subject id for user %s',
            request.user)

    result = client.global_logout(subject_id)

    state.sync()

    if not result:
        logger.error("Looks like the user %s is not logged in any IdP/AA", subject_id)
        return HttpResponseBadRequest("You are not logged in any IdP/AA")

    if len(result) > 1:
        logger.error('Sorry, I do not know how to logout from several sources. I will logout just from the first one')

    for entityid, logout_info in result.items():
        if isinstance(logout_info, tuple):
            binding, http_info = logout_info
            if binding == BINDING_HTTP_POST:
                logger.debug('Returning form to the IdP to continue the logout process')
                body = ''.join(http_info['data'])
                return HttpResponse(body)
            elif binding == BINDING_HTTP_REDIRECT:
                logger.debug('Redirecting to the IdP to continue the logout process')
                return HttpResponseRedirect(get_location(http_info))
            else:
                logger.error('Unknown binding: %s', binding)
                return HttpResponseServerError('Failed to log out')
        else:
            # We must have had a soap logout
            return finish_logout(request, logout_info)

    logger.error('Could not logout because there only the HTTP_REDIRECT is supported')
    return HttpResponseServerError('Logout Binding not supported')
Beispiel #9
0
    def __init__(
        self,
        srv,
        lookup,
        userdb,
        spconf,
        url,
        return_to,
        cache=None,
        bindings=None,
        userinfo=None,
        samlcache=None,
    ):
        """
        Construct the class.

        :param srv: Usually none, but otherwise the oic server.
        :param return_to: The URL to return to after a successful
        authentication.
        """
        self.userdb = userdb
        self.userinfo = userinfo

        if cache is None:
            self.cache_outstanding_queries = {}  # type: Mapping[str, str]
        else:
            self.cache_outstanding_queries = cache
        UserAuthnMethod.__init__(self, srv)
        self.return_to = return_to
        self.idp_query_param = "IdpQuery"
        if bindings:
            self.bindings = bindings
        else:
            self.bindings = [
                BINDING_HTTP_REDIRECT,
                BINDING_HTTP_POST,
                BINDING_HTTP_ARTIFACT,
            ]
        # TODO Why does this exist?
        self.verification_endpoint = ""
        # Configurations for the SP handler.
        self.sp_conf = importlib.import_module(spconf)
        config = SPConfig().load(self.sp_conf.CONFIG)
        self.sp = Saml2Client(config=config)
        mte = lookup.get_template("unauthorized.mako")
        argv = {"message": "You are not authorized!"}
        self.not_authorized = mte.render(**argv)
        self.samlcache = self.sp_conf.SAML_CACHE
Beispiel #10
0
def get_saml_login_request(binding=BINDING_HTTP_REDIRECT):
    conf = SPConfig()
    conf.load(copy.deepcopy(sp_conf_dict))
    client = Saml2Client(conf)
    if binding == BINDING_HTTP_REDIRECT:
        session_id, result = client.prepare_for_authenticate(
            entityid="test_generic_idp",
            relay_state="",
            binding=binding,
        )
        return parse.parse_qs(parse.urlparse(
            result['headers'][0][1]).query)['SAMLRequest'][0]
    elif binding == BINDING_HTTP_POST:
        session_id, request_xml = client.create_authn_request(
            "http://localhost:9000/idp/sso/post", binding=binding)
    return base64.b64encode(bytes(request_xml, 'UTF-8'))
def instantiate(p):
    """Module Instantiation.  0 for success, -1 for failure.
    """
    global CLIENT
    global ECP

    # Use IdP info retrieved from the SP when metadata is missing

    try:
        CLIENT = Saml2Client(config_file=config.CONFIG)
    except Exception, err:
        # Report the error and return -1 for failure.
        # xxx A more advanced module would retry the database.
        exception_trace("instantiate", err, LOG())
        log(radiusd.L_ERR, str(err))
        return -1
Beispiel #12
0
def test_basic():
    sp = Saml2Client(config_file="servera_conf")
    with closing(Server(config_file="idp_all_conf")) as idp:
        srvs = sp.metadata.authn_query_service(idp.config.entityid)

        destination = srvs[0]["location"]
        authn_context = requested_authn_context(INTERNETPROTOCOLPASSWORD)

        subject = Subject(text="abc",
                          name_id=NameID(format=NAMEID_FORMAT_TRANSIENT))

        _id, aq = sp.create_authn_query(subject, destination, authn_context)

        print(aq)

        assert isinstance(aq, AuthnQuery)
Beispiel #13
0
def test_construct_deconstruct_response():
    sp = Saml2Client(config_file=dotname("servera_conf"))
    url = sp.create_discovery_service_request(
        "http://example.com/saml/disco",
        "https://example.com/saml/sp.xml",
        is_passive=True,
        returnIDParam="foo",
        return_url="https://example.com/saml/sp/disc")
    ds = DiscoveryServer(config_file=dotname("disco_conf"))
    dsr = ds.parse_discovery_service_request(url)
    args = dict([(key, dsr[key]) for key in ["returnIDParam", "return"]])
    url = ds.create_discovery_service_response(
        entity_id="https://example.com/saml/idp.xml", **args)

    idp_id = sp.parse_discovery_service_response(url, returnIDParam="foo")
    assert idp_id == "https://example.com/saml/idp.xml"
Beispiel #14
0
def test_construct_deconstruct_request():
    sp = Saml2Client(config_file=dotname("servera_conf"))
    url = sp.create_discovery_service_request(
        "http://example.com/saml/disco",
        "https://example.com/saml/sp.xml",
        is_passive=True,
        returnIDParam="foo",
        return_url="https://example.com/saml/sp/disc")

    print(url)

    ds = DiscoveryServer(config_file=dotname("disco_conf"))
    dsr = ds.parse_discovery_service_request(url)
    # policy is added by the parsing and verifying method
    assert _eq(list(dsr.keys()),
               ["return", "entityID", "returnIDParam", "isPassive", "policy"])
Beispiel #15
0
def _get_saml_client(domain):
    acs_url = domain + get_reverse([acs, 'acs', 'django_saml2_auth:acs'])
    metadata = _get_metadata()

    authn_requests_signed = settings.SAML2_AUTH.get('AUTHN_REQUESTS_SIGNED',
                                                    False)

    saml_settings = {
        'metadata': metadata,
        'service': {
            'sp': {
                'endpoints': {
                    'assertion_consumer_service':
                    [(acs_url, BINDING_HTTP_REDIRECT),
                     (acs_url, BINDING_HTTP_POST)],
                },
                'allow_unsolicited': True,
                'authn_requests_signed': authn_requests_signed,
                'logout_requests_signed': True,
                'want_assertions_signed': True,
                'want_response_signed': False,
            },
        },
    }

    if 'ENTITY_ID' in settings.SAML2_AUTH:
        saml_settings['entityid'] = settings.SAML2_AUTH['ENTITY_ID']

    if 'NAME_ID_FORMAT' in settings.SAML2_AUTH:
        saml_settings['service']['sp']['name_id_format'] = settings.SAML2_AUTH[
            'NAME_ID_FORMAT']

    if 'ACCEPTED_TIME_DIFF' in settings.SAML2_AUTH:
        saml_settings['accepted_time_diff'] = settings.SAML2_AUTH[
            'ACCEPTED_TIME_DIFF']

    if settings.SAML2_AUTH.get('CERT_FILE'):
        saml_settings['cert_file'] = settings.SAML2_AUTH['CERT_FILE']

    if settings.SAML2_AUTH.get('KEY_FILE'):
        saml_settings['key_file'] = settings.SAML2_AUTH['KEY_FILE']

    spConfig = Saml2Config()
    spConfig.load(saml_settings)
    spConfig.allow_unknown_attributes = True
    saml_client = Saml2Client(config=spConfig)
    return saml_client
Beispiel #16
0
 def __init__(self, sp_logger, args):
     """
     Constructor for the SpHandler.
     :param sp_logger: A logger.
     """
     #Metadata for the SP
     self.sp_metadata = create_metadata_string(args.spconf + ".py", None,
                                               args.valid, args.cert,
                                               args.keyfile, args.id_sp,
                                               args.name_sp, args.sign)
     #Log class. (see import logging)
     self.logger = sp_logger
     #Configurations for the SP handler. (pyOpSamlProxy.client.sp.conf)
     self.sp_conf = importlib.import_module(
         args.spconf)  #pyOpSamlProxy.client.sp.conf
     #Name of the configuration file. See above.
     self.sp_conf_name = self.sp_conf.WORKING_DIR + args.spconf
     #SP configuration object. (See project pysaml2; saml2.client.Saml2Client)
     self.sp = Saml2Client(config_file="%s" % self.sp_conf_name)
     #Extra arguments for the pyOpSamlProxy.client.sp.util.SSO object.
     self.args = {}
     #URL to SAML discovery server.
     self.args["discosrv"] = self.sp_conf.DISCOSRV
     #URL to SAML WAYF server.
     self.args["wayf"] = self.sp_conf.WAYF
     #URL to op server authorization when the SP have been authenticated.
     #TODO have to be changed when Saml to Saml is implemented.
     self.authorization_url = "%s/authorization" % self.sp_conf.ISSUER
     #Handles the SAML authentication for an op server.
     self.authnmethod = SPAuthnMethodHandler(None,
                                             self.sp_conf.SPVERIFYBASE,
                                             self.authorization_url)
     #Handles SAML authentication for an IdP server.
     # Setup performed by pyOpSamlProxy.provider.idp.handler.handler.
     self.sp_authentication = None
     #Handles the user info response with Saml attributes.
     self.userinfo = UserInfoSpHandler(self.sp_conf.OPENID2SAMLMAP, self)
     #The handler for the op server. Must be set after creation
     #This must be the instance of the class pyOpSamlProxy.provider.op.handler.OpHandler.
     self.ophandler = None
     #Contains the user cache for the SpHandler, like collected IdP attributes.
     #Dictionary where userid is key and value is an instance of the class
     #pyOpSamlProxy.client.sp.handler.SpHandlerCache
     self.sphandlercache = self.sp_conf.CACHE
     self.certificate_cache_name = "CERTIFICATE_CACHE"
     self.certificate_cookie_name = sid()
     self.certificate_cookie_seed = sid()
Beispiel #17
0
 def s_client(self):
     """
     Setup and return the SAML client with specified config
     """
     acs_url = url_for('sso', _scheme='https', _external=True)
     logger.debug('SSO ACS URL: {}'.format(acs_url))
     logout_url = url_for('logout', _scheme='https', _external=True)
     try:
         with open(self.meta_file, 'r') as meta_fh:
             if len(meta_fh.read()) > 0:
                 pass
     except FileError as err:
         res = requests.get(self.meta_url)
         with open(self.meta_file, 'w') as meta_fh:
             meta_fh.write(res.text)
     ###***review all of these settings
     settings = {
         'metadata': {
             "local": [self.meta_file]
         },
         'service': {
             'sp': {
                 'name_id_format': 'None',
                 'endpoints': {
                     'assertion_consumer_service':
                     [(acs_url, BINDING_HTTP_REDIRECT),
                      (acs_url, BINDING_HTTP_POST)],
                     'single_logout_service':
                     [(logout_url, BINDING_HTTP_REDIRECT)]
                 },
                 ###***update some of these if possible
                 'allow_unsolicited': True,
                 #'allow_unknown_attributes': True,
                 'authn_requests_signed': False,
                 'logout_requests_signed': True,
                 'want_assertions_signed': True,
                 'want_response_signed': False,
                 'attribute_map_dir': './attributemaps',
             },
         },
     }
     sp_config = Saml2Config()
     sp_config.load(settings)
     sp_config.entityid = self.entity_id
     sp_config.allow_unknown_attributes = True
     client = Saml2Client(config=sp_config)
     return client
Beispiel #18
0
def saml2_client_for(idp_name=None):
    '''
    Given the name of an Identity Provider look up the Saml2Configuration and build a SAML Client. Return these.
    '''

    # SAML metadata changes very rarely, check for cached version first
    config = Saml2Configuration.objects.get(slug=idp_name)
    metadata = None
    if config:
        metadata = config.cached_metadata

    if not metadata:
        r = requests.get(config.metadata_conf_url)
        metadata = r.text

    origin = getattr(settings, 'HTTP_ORIGIN').split('://')[1]
    https_acs_url = 'https://' + origin + reverse('assertion_consumer_service', args=[idp_name])

    setting = {
        'metadata': {
            'inline': [metadata],
        },
        'entityid': "badgrserver",
        'service': {
            'sp': {
                'endpoints': {
                    'assertion_consumer_service': [
                        (https_acs_url, BINDING_HTTP_POST)
                    ],
                },
                # Don't verify that the incoming requests originate from us via
                # the built-in cache for authn request ids in pysaml2
                'allow_unsolicited': True,
                # Don't sign authn requests, since signed requests only make
                # sense in a situation where you control both the SP and IdP
                'authn_requests_signed': False,
                'logout_requests_signed': True,
                'want_assertions_signed': True,
                'want_response_signed': False,
            },
        },
    }
    spConfig = Saml2Config()
    spConfig.load(setting)
    spConfig.allow_unknown_attributes = True
    saml_client = Saml2Client(config=spConfig)
    return saml_client, config
Beispiel #19
0
def get_saml_client(org):
    """
    Return SAML configuration.

    The configuration is a hash for use by saml2.config.Config
    """
    metadata_url = org.get_setting("auth_saml_metadata_url")
    entity_id = org.get_setting("auth_saml_entity_id")
    acs_url = url_for("saml_auth.idp_initiated",
                      org_slug=org.slug,
                      _external=True)

    saml_settings = {
        'metadata': {
            "remote": [{
                "url": metadata_url
            }]
        },
        'service': {
            'sp': {
                'endpoints': {
                    'assertion_consumer_service':
                    [(acs_url, BINDING_HTTP_REDIRECT),
                     (acs_url, BINDING_HTTP_POST)],
                },
                # Don't verify that the incoming requests originate from us via
                # the built-in cache for authn request ids in pysaml2
                'allow_unsolicited': True,
                # Don't sign authn requests, since signed requests only make
                # sense in a situation where you control both the SP and IdP
                'authn_requests_signed': False,
                'logout_requests_signed': True,
                'want_assertions_signed': True,
                'want_response_signed': False,
            },
        },
    }

    if entity_id is not None and entity_id != "":
        saml_settings['entityid'] = entity_id

    sp_config = Saml2Config()
    sp_config.load(saml_settings)
    sp_config.allow_unknown_attributes = True
    saml_client = Saml2Client(config=sp_config)

    return saml_client
Beispiel #20
0
    def get_saml_client(self, handler):
        acs_url = self.get_current_domain(handler) + handler.reverse_url(
            'saml2_acs_handler')
        if self.saml2_metadata_filename:
            metadata = {'local': [self.saml2_metadata_filename]}
        elif self.saml2_metadata_url:
            metadata = {
                'remote': [
                    {
                        "url": self.saml2_metadata_url,
                    },
                ]
            }
        else:
            raise web.HTTPError(500, 'No metadata provided')

        saml_settings = {
            'metadata': metadata,
            'service': {
                'sp': {
                    'endpoints': {
                        'assertion_consumer_service':
                        [(acs_url, BINDING_HTTP_REDIRECT),
                         (acs_url, BINDING_HTTP_POST)],
                    },
                    'allow_unsolicited': True,
                    'authn_requests_signed': False,
                    'logout_requests_signed': True,
                    'want_assertions_signed': True,
                    'want_response_signed': False,
                },
            },
        }

        if self.saml2_entity_id:
            saml_settings['entityid'] = self.saml2_entity_id

        if self.saml2_name_id_format:
            saml_settings['service']['sp'][
                'name_id_format'] = self.saml2_name_id_format

        spConfig = Saml2Config()
        spConfig.load(saml_settings)
        spConfig.allow_unknown_attributes = True
        saml_client = Saml2Client(config=spConfig)
        return saml_client
Beispiel #21
0
def echo_attributes(request,
                    config_loader_path=None,
                    template='djangosaml2/echo_attributes.html'):
    """Example view that echo the SAML attributes of an user"""
    state = StateCache(request.session)
    conf = get_config(config_loader_path, request)

    client = Saml2Client(conf, state_cache=state,
                         identity_cache=IdentityCache(request.session))
    subject_id = _get_subject_id(request.session)
    try:
        identity = client.users.get_identity(subject_id,
                                             check_not_on_or_after=False)
    except AttributeError:
        return HttpResponse("No active SAML identity found. Are you sure you have logged in via SAML?")

    return render(request, template, {'attributes': identity[0]})
Beispiel #22
0
def create_logout_request(subject_id,
                          destination,
                          issuer_entity_id,
                          req_entity_id,
                          sign=True):
    config = SPConfig()
    config.load(sp_config)
    sp_client = Saml2Client(config=config)
    # construct a request
    logout_request = samlp.LogoutRequest(id='a123456',
                                         version=VERSION,
                                         destination=destination,
                                         issuer=saml.Issuer(
                                             text=req_entity_id,
                                             format=saml.NAMEID_FORMAT_ENTITY),
                                         name_id=saml.NameID(text=subject_id))
    return logout_request
def test_request_response():
    sp = Saml2Client(config_file="servera_conf")

    with closing(Server(config_file="idp_all_conf")) as idp:
        binding, destination = sp.pick_binding("name_id_mapping_service",
                                               entity_id=idp.config.entityid)

        policy = NameIDPolicy(format=NAMEID_FORMAT_TRANSIENT,
                              sp_name_qualifier="urn:mace:swamid:junk",
                              allow_create="true")

        nameid = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar")

        mid, nmr = sp.create_name_id_mapping_request(policy, nameid,
                                                     destination)

        print nmr

        args = sp.use_soap(nmr, destination)

        # ------- IDP ------------

        req = idp.parse_name_id_mapping_request(args["data"], binding)

        in_response_to = req.message.id
        name_id = NameID(format=NAMEID_FORMAT_PERSISTENT, text="foobar")

        idp_response = idp.create_name_id_mapping_response(
            name_id, in_response_to=in_response_to)

        print idp_response

        ht_args = sp.use_soap(idp_response)

        # ------- SP ------------

        _resp = sp.parse_name_id_mapping_request_response(
            ht_args["data"], binding)

        print _resp.response

        r_name_id = _resp.response.name_id

        assert r_name_id.format == NAMEID_FORMAT_PERSISTENT
        assert r_name_id.text == "foobar"
Beispiel #24
0
def _get_saml_client(domain):
    acs_url = domain + get_reverse([acs, 'acs', 'django_saml2_auth:acs'])

    saml_settings = {
        'metadata': {},
        'service': {
            'sp': {
                'endpoints': {
                    'assertion_consumer_service':
                    [(acs_url, BINDING_HTTP_REDIRECT),
                     (acs_url, BINDING_HTTP_POST)],
                },
                'allow_unsolicited': True,
                'authn_requests_signed': False,
                'logout_requests_signed': True,
                'want_assertions_signed': True,
                'want_response_signed': False,
            },
        },
    }

    if 'METADATA_AUTO_CONF_URL' in settings.SAML2_AUTH:
        saml_settings['metadata']['remote'] = settings.SAML2_AUTH[
            'METADATA_AUTO_CONF_URL']

    if 'METADATA_AUTO_CONF_INLINE' in settings.SAML2_AUTH:
        saml_settings['metadata']['inline'] = settings.SAML2_AUTH[
            'METADATA_AUTO_CONF_INLINE']

    if 'METADATA_AUTO_CONF_LOCAL' in settings.SAML2_AUTH:
        saml_settings['metadata']['local'] = settings.SAML2_AUTH[
            'METADATA_AUTO_CONF_LOCAL']

    if 'ENTITY_ID' in settings.SAML2_AUTH:
        saml_settings['entityid'] = settings.SAML2_AUTH['ENTITY_ID']

    if 'NAME_ID_FORMAT' in settings.SAML2_AUTH:
        saml_settings['service']['sp']['name_id_format'] = settings.SAML2_AUTH[
            'NAME_ID_FORMAT']

    spConfig = Saml2Config()
    spConfig.load(saml_settings)
    spConfig.allow_unknown_attributes = True
    saml_client = Saml2Client(config=spConfig)
    return saml_client
Beispiel #25
0
def test_base_request():
    sp = Saml2Client(config_file="servera_conf")
    idp = Server(config_file="idp_all_conf")

    binding, destination = sp.pick_binding("name_id_mapping_service",
                                           entity_id=idp.config.entityid)

    policy = NameIDPolicy(format=NAMEID_FORMAT_TRANSIENT,
                          sp_name_qualifier="urn:mace:swamid:junk",
                          allow_create="true")

    nameid = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar")

    nmr = sp.create_name_id_mapping_request(policy, nameid, destination)

    print nmr

    assert isinstance(nmr, NameIDMappingRequest)
Beispiel #26
0
async def saml_client(kind='admin'):

    if kind == 'admin':
        url = SAML_METADATA_URL_ADMIN
        acs_url = SAML_ACS_URL_ADMIN
        entity_id = SAML_ENTITY_ID_ADMIN
    else:
        url = SAML_METADATA_URL_FILER
        acs_url = SAML_ACS_URL_ADMIN
        entity_id = SAML_ENTITY_ID_FILER

    meta = await get_metadata(url)

    settings = {
        'entityid': entity_id,
        'metadata': {
            'inline': [meta],
        },
        'service': {
            'sp': {
                'endpoints': {
                    'assertion_consumer_service': [
                        (acs_url, BINDING_HTTP_REDIRECT),
                        (acs_url, BINDING_HTTP_POST),
                    ],
                },
                # Don't verify that the incoming requests originate from us via
                # the built-in cache for authn request ids in pysaml2
                'allow_unsolicited': True,
                # Don't sign authn requests, since signed requests only make
                # sense in a situation where you control both the SP and IdP
                'authn_requests_signed': False,
                'logout_requests_signed': True,
                'want_assertions_signed': True,
                'want_response_signed': False,
            },
        },
    }

    spConfig = Saml2Config()
    spConfig.load(settings)
    spConfig.allow_unknown_attributes = True
    saml_client = Saml2Client(config=spConfig)
    return saml_client
Beispiel #27
0
def test_flow():
    sp = Saml2Client(config_file="servera_conf")
    try:
        with closing(Server(config_file="idp_conf_mdb")) as idp1:
            with closing(Server(config_file="idp_conf_mdb")) as idp2:
                # clean out database
                idp1.ident.mdb.db.drop()

                # -- dummy request ---
                req_id, orig_req = sp.create_authn_request(
                    idp1.config.entityid)

                # == Create an AuthnRequest response

                rinfo = idp1.response_args(orig_req, [BINDING_HTTP_POST])

                #name_id = idp1.ident.transient_nameid("id12", rinfo["sp_entity_id"])
                resp = idp1.create_authn_response(
                    {
                        "eduPersonEntitlement": "Short stop",
                        "surName": "Jeter",
                        "givenName": "Derek",
                        "mail": "*****@*****.**",
                        "title": "The man"
                    },
                    userid="jeter",
                    authn=AUTHN,
                    **rinfo)

                # What's stored away is the assertion
                a_info = idp2.session_db.get_assertion(resp.assertion.id)
                # Make sure what I got back from MongoDB is the same as I put in
                assert a_info["assertion"] == resp.assertion

                # By subject
                nid = resp.assertion.subject.name_id
                _assertion = idp2.session_db.get_assertions_by_subject(nid)
                assert len(_assertion) == 1
                assert _assertion[0] == resp.assertion

                nids = idp2.ident.find_nameid("jeter")
                assert len(nids) == 1
    except ConnectionFailure:
        pass
Beispiel #28
0
def login(request,
          config_loader_path=None,
          wayf_template='djangosaml2/wayf.html',
          authorization_error_template='djangosaml2/auth_error.html'):
    """SAML Authorization Request initiator

    This view initiates the SAML2 Authorization handshake
    using the pysaml2 library to create the AuthnRequest.
    It uses the SAML 2.0 Http Redirect protocol binding.
    """
    logger.debug('Login process started')

    came_from = request.GET.get('next', settings.LOGIN_REDIRECT_URL)

    if not request.user.is_anonymous():
        logger.debug('User is already logged in')
        return render_to_response(authorization_error_template, {
            'came_from': came_from,
        },
                                  context_instance=RequestContext(request))

    selected_idp = request.GET.get('idp', None)
    conf = get_config(config_loader_path, request)

    # is a embedded wayf needed?
    idps = conf.idps()
    if selected_idp is None and len(idps) > 1:
        logger.debug('A discovery process is needed')
        return render_to_response(wayf_template, {
            'available_idps': idps.items(),
            'came_from': came_from,
        },
                                  context_instance=RequestContext(request))

    client = Saml2Client(conf, logger=logger)
    try:
        (session_id, result) = client.authenticate(
            entityid=selected_idp,
            relay_state=came_from,
            binding=BINDING_HTTP_REDIRECT,
        )
    except TypeError, e:
        logger.error('Unable to know which IdP to use')
        return HttpResponse(unicode(e))
def _get_saml_client(domain):
    acs_url = domain + get_reverse([acs, 'acs', 'django_saml2_auth:acs'])
    metadata = _get_metadata()

    saml_settings = {
        'metadata': metadata,
        'service': {
            'sp': {
                'endpoints': {
                    'assertion_consumer_service':
                    [(acs_url, BINDING_HTTP_REDIRECT),
                     (acs_url, BINDING_HTTP_POST)],
                },
                'allow_unsolicited': True,
                'authn_requests_signed': False,
                'logout_requests_signed': True,
                'want_assertions_signed': True,
                'want_response_signed': False,
            },
        },
    }

    if 'ENTITY_ID' in settings.SAML2_AUTH:
        saml_settings['entityid'] = settings.SAML2_AUTH['ENTITY_ID']

    if 'NAME_ID_FORMAT' in settings.SAML2_AUTH:
        saml_settings['service']['sp']['name_id_format'] = settings.SAML2_AUTH[
            'NAME_ID_FORMAT']

    if 'WANT_ASSERTIONS_SIGNED' in settings.SAML2_AUTH:
        saml_settings['service']['sp'][
            'want_assertions_signed'] = settings.SAML2_AUTH[
                'WANT_ASSERTIONS_SIGNED']

    if 'WANT_RESPONSE_SIGNED' in settings.SAML2_AUTH:
        saml_settings['service']['sp'][
            'want_response_signed'] = settings.SAML2_AUTH[
                'WANT_RESPONSE_SIGNED']

    spConfig = Saml2Config()
    spConfig.load(saml_settings)
    spConfig.allow_unknown_attributes = True
    saml_client = Saml2Client(config=spConfig)
    return saml_client
Beispiel #30
0
 def get_login_url(self):
     """returns the url for login"""
     client = Saml2Client(config_file=config_file)
     if not self.entityid:
         idps = client.metadata.with_descriptor("idpsso")
         self.entityid = idps.keys()[0]
     bindings = [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST]
     binding, destination = client.pick_binding("single_sign_on_service",
                                                bindings,
                                                "idpsso",
                                                entity_id=entityid)
     req_id, req = client.create_authn_request(destination,
                                               binding=BINDING_HTTP_POST)
     relay_state = web2py_uuid().replace("-", "")
     http_args = client.apply_binding(binding,
                                      str(req),
                                      destination,
                                      relay_state=relay_state)
     return http_args["headers"]["Location"]