_潜行者

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

第一步安装signxml、BeautifulSoup(3.2.1)模块

from signxml import XMLVerifier
from BeautifulSoup import BeautifulStoneSoup
from django.contrib.auth import authenticate


def get_sso_response(request):
    data = request.POST.get('SAMLResponse', None)
    assertion = base64.b64decode(data)
    try:
        huaweicertpath = sso_setting.IDP_CERT_FILE
        x509certcontent = open(huaweicertpath, 'rt').read()
        verified_data = XMLVerifier().verify(assertion, x509_cert=x509certcontent).signed_xml
    except Exception as e:
        logger.error('验证失败')
        logger.error(traceback.format_exc())
        error = 'SSO登录失败'
        return render(request, 'login.html', {'error': error})

    attributes = _get_attributes_from_assertion(assertion)
    user = _get_user_from_assertion(assertion, attributes)
    (returncode, returnmsg) = validateResponse(assertion)
    if returncode != 1:
        return render(request, 'login.html', {'error': returnmsg})

    user = authenticate(username=user.username, token=CRYPTOR.gen_rand_pass(16))
    if user is None:
        raise Exception('Unable to login user "%s" with SAML2SP_SAML_USER_PASSWORD' % user.email)
    login(request, user)

    if user.role == 'SU':
        request.session['role_id'] = 2
    elif user.role == 'GA':
        request.session['role_id'] = 1
    else:
        request.session['role_id'] = 0
    return HttpResponseRedirect(reverse('index'))


def _get_attributes_from_assertion(assertion):
    """
    Returns the SAML Attributes (if any) that are present in the assertion.

    NOTE: Technically, attribute values could be any XML structure.
          But for now, just assume a single string value.
    """
    attributes = {}
    soup = BeautifulStoneSoup(assertion)
    attrs = soup.findAll('saml:attribute')
    for attr in attrs:
        name = attr['name']
        values = attr.findAll('saml:attributevalue')
        if len(values) == 0:
            # Ignore empty-valued attributes. (I think these are not allowed.)
            continue
        elif len(values) == 1:
            # See NOTE:
            attributes[name] = values[0].string
        else:
            # It has multiple values.
            for value in values:
                # See NOTE:
                attributes.setdefault(name, []).append(value.string)
    return attributes


def validateResponse(rawxml):
    current_date = datetime.datetime.utcnow()
    valid_from = _get_valid_start_from_assertion(rawxml)
    valid_until = _get_valid_end_from_assertion(rawxml)

    valid_from_date = datetime.datetime.strptime(valid_from, '%Y-%m-%dT%H:%M:%SZ')
    valid_until_date = datetime.datetime.strptime(valid_until, '%Y-%m-%dT%H:%M:%SZ')

    if 'www.huawei.com' != _get_saml_issuer_from_assertion(rawxml).lower():
        return (-1, 'saml issuer error')
    elif current_date.date() < valid_from_date.date():
        return (-2, 'not valid before ' + valid_from_date.strftime("%Y-%m-%d %H:%M:%S"))
    elif current_date.date() > valid_until_date.date():
        return (-3, 'not valid after ' + valid_until_date.strftime("%Y-%m-%d %H:%M:%S"))
    else:
        return (1, 'ok')


def get_saml_requst(request):
    lines = sso_setting.SSO_REQUEST_TEMPLATE
    keycontent = open(sso_setting.SSO_KEY, 'rt').read()
    certcontent = open(sso_setting.SSO_CERT, 'rt').read()
    requestcontent = base64.encodestring(get_saml_request_content(keycontent, certcontent, lines))
    next = ''
    request_url = sso_setting.IDP_URL
    return render(request, 'sso_post_request.html', locals())


def get_saml_request_content(key_content, cert_content, raw_xml):
    root = etree.fromstring(raw_xml)
    signed_root = signxml.XMLSigner(method=signxml.methods.enveloped, signature_algorithm=u'rsa-sha1',
                                    digest_algorithm=u'sha1',
                                    c14n_algorithm=u'http://www.w3.org/2001/10/xml-exc-c14n#').sign(root,
                                                                                                    key=key_content,
                                                                                                    passphrase='123456',
                                                                                                    cert=cert_content)
    return etree.tostring(signed_root)

 

posted on 2018-12-19 16:06  _潜行者  阅读(2032)  评论(1)    收藏  举报