• CAS 6.x + Delegated Authentication SAML2.0 配置记录


    最近领导派了一个活儿, 需要把我们CAS系统的身份识别交给甲方的系统, 甲方的系统是SAML2.0的协议。

    由于之前对SAML2.0协议了解不多,折腾了不少时间,在这里记录一下。以后忘掉还可以看看。

    首先是关于SAML2.0协议的简单介绍,在B站找到一个还不错的视频。https://www.bilibili.com/video/BV1sA411Y758/

     

    1.配置cas.properties,让cas作为 SAML2.0 的 IDP(身份提供方)

      这一步其实没啥用, 因为我是要对接别人的IDP 而不是让自己的cas成为IDP,如果需要自己建一个cas作为IDP的话可以参考

    cas.properties:  cas.authn.saml-idp.core.entity-id=${cas.server.name}/idp

    build.gradle: implementation "org.apereo.cas:cas-server-support-saml-idp:${project.'cas.version'}"
    配置完之后可以打开idp路径查看idp/metadata-> http://localhost:8888/cas/idp/metadata

      上面两个配置完成后其实作为IDP还是不能运作的(未授权的服务),你要对外提供身份验证的话,除了别人配置你作为IDP, 你也需要知道是哪个服务在用你, 你还需要给SP(服务提供方)权限,并且配置sp的metadata

     在/etc/cas/services下面配置sp的信息,测试环境的话可以配置得粗暴一点:

    saml2-10004.json:
    {
      "@class" : "org.apereo.cas.support.saml.services.SamlRegisteredService",
      "serviceId" : ".+",
      "name" : "SAMLService",
      "id" : 10000003,
      "evaluationOrder" : 10,
      "metadataLocation" : "file:/etc/cas/config/sp-metadata-local.xml" 
    }
    View Code

     sp-metadata-local.xml: 这个文件一般是sp提供的。里面一般包含EntityID, 签名和加密的共钥,以及支持的NameID格式。需要的属性字段(这里没有配属性字段)。

    xml version="1.0" encoding="UTF-8"?>
    <md:EntityDescriptor ID="_cb7748cb6778495398727ae8bfcaa72e62beea3" entityID="liveramp-sp"
                         validUntil="2043-03-16T11:36:25.739Z" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
        <md:Extensions xmlns:alg="urn:oasis:names:tc:SAML:metadata:algsupport">
            <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#hmac-sha384"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#hmac-sha512"/>
            <alg:SigningMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>
            <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
            <alg:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#sha384"/>
            <alg:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        md:Extensions>
        <md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false"
                            protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.0:protocol urn:oasis:names:tc:SAML:1.1:protocol">
            <md:Extensions xmlns:init="urn:oasis:names:tc:SAML:profiles:SSO:request-init">
                <init:RequestInitiator Binding="urn:oasis:names:tc:SAML:profiles:SSO:request-init"
                                       Location="http://localhost:8888/cas/login?client_name=IHG-SAML2.0-CLIENT"/>
            md:Extensions>
            <md:KeyDescriptor use="signing">
                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <ds:X509Data>
                        <ds:X509Certificate>xxxx
                        ds:X509Certificate>
                    ds:X509Data>
                ds:KeyInfo>
            md:KeyDescriptor>
            <md:KeyDescriptor use="encryption">
                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <ds:X509Data>
                        <ds:X509Certificate>xxxx
                        ds:X509Certificate>
                    ds:X509Data>
                ds:KeyInfo>
            md:KeyDescriptor>
            <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                                    Location="http://localhost:8888/cas/login?client_name=IHG-SAML2.0-CLIENT&logoutendpoint=true"/>
            <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
                                    Location="http://localhost:8888/cas/login?client_name=IHG-SAML2.0-CLIENT&logoutendpoint=true"/>
            <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
                                    Location="http://localhost:8888/cas/login?client_name=IHG-SAML2.0-CLIENT&logoutendpoint=true"/>
            <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
                                    Location="http://localhost:8888/cas/login?client_name=IHG-SAML2.0-CLIENT&logoutendpoint=true"/>
            <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transientmd:NameIDFormat>
            <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistentmd:NameIDFormat>
            <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddressmd:NameIDFormat>
            <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecifiedmd:NameIDFormat>
            <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                                         Location="http://localhost:8888/cas/login?client_name=IHG-SAML2.0-CLIENT"
                                         index="0"/>
        md:SPSSODescriptor>
    md:EntityDescriptor>
    View Code

      如果里面含有属性字段, sp-metadata.xml会多出一些内容:

            <md:AttributeConsumingService index="0">
                <md:RequestedAttribute Name="firstName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
                                       isRequired="false"/>
                <md:RequestedAttribute Name="lastName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
                                       isRequired="false"/>
                <md:RequestedAttribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
                                       isRequired="false"/>
                <md:RequestedAttribute FriendlyName="displayName" Name="urn:oid:2.16.840.1.113730.3.1.241"
                                       NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/>
                <md:RequestedAttribute FriendlyName="cn" Name="cn"
                                       NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false"/>
            md:AttributeConsumingService>
    View Code

     

    2. 配置委托认证

      1). cas的委托认证都是通过pac4j去做的, 所以先要加上pac4j的依赖。

       build.gradle里加上依赖:  implementation "org.apereo.cas:cas-server-support-pac4j-webflow:${project.'cas.version'}" 

      2) 修改cas.properties加上委托认证的配置

    cas.authn.pac4j.core.lazy-init=false
    cas.authn.pac4j.saml[0].client-name=SAML2.0-CLIENT
    cas.authn.pac4j.saml[0].display-name=SAML
    
    # 如果是文件 file:/xxx/xxx.xml
    cas.authn.pac4j.saml[0].identity-provider-metadata-path=https://yd-dev.liverampapac.com/sso/idp/metadata
    
    
    cas.authn.pac4j.saml[0].keystore-path=file:/private/etc/cas/config/saml2.0/cer/samlKeystore.jks
    cas.authn.pac4j.saml[0].keystore-password=xxx
    cas.authn.pac4j.saml[0].private-key-password=xxx
    cas.authn.pac4j.saml[0].service-provider-entity-id=xxxxx
    # this is important
    cas.authn.pac4j.saml[0].service-provider-metadata-path=file:/etc/cas/config/saml2.0/sp-metadata.xml
    # If false global logout may not work, it's depends on IDP settings
    cas.authn.pac4j.saml[0].sign-service-provider-logout-request=true
    View Code

      使用委托认证就是要把认证的行为交给IDP, 而自己成为SP. IDP跟SP之间的通信的安全,或者说他们之前的信任是需要证书支持的,一般在IDP和SP的metadata都会配置证书的公钥,当信息传到自己系统时, 用自己的私钥做验签/解密。

      上面在cas.properties的改动里还有一个 sp-metadata.xml需要我们自己构建(下面这个sp-metadata.xml 最低配置其实只需要配两个公钥就能工作了,其它的cas会帮我们自动生成)

    
    
                         entityID="liveramp-sp"
                         xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
        
                            protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.0:protocol urn:oasis:names:tc:SAML:1.1:protocol">
            
                
                    
                        xxx
                        
                    
                
            
            
                
                    
                        xxx
                        
                    
                
            
            
            
    
            
            
            urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
            urn:oasis:names:tc:SAML:2.0:nameid-format:transient
            urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
            urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
            urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
            
            
    
    
    
            
                                          xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
                                          xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
                
                
                                       NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
                                       Name="cn"
                                       FriendlyName="cn"/>
                <md:RequestedAttribute
                        NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
                        Name="urn:oid:2.16.840.1.113730.3.1.241"
                        FriendlyName="displayName"/>
                
                
                
            
        
    
    View Code

      证书的生成如果觉得麻烦的话, 这里有一键生成工具,两个文件放一个目录下面 然后一键生成 ./gen.sh [*name] [*domain] [*passwd] ,生成出来把crt文件的内容放到里面。jks文件路径和passwd也都需要配置到

    cas.porperties里面.

      gen.sh:

    #!/bin/bash
    echo "自动创建自定义证书"
    region=$1
    region_suffix=$2
    pass=$3
    
    if [[ "X$region" == "X" ]]; then
      echo "region is empty"
      exit 1
    fi
    
    if [[ "X$region_suffix" == "X" ]]; then
      echo "region_suffix is empty"
      exit 1
    fi
    
    if [[ ! -f "openssl.cnf" ]]; then
      echo "openssl.cnf file is not exist"
      exit 1
    fi
    
    mkdir $region
    
    cp openssl.cnf $region/
    
    cd $region
    
    mkdir demoCA
    
    cd demoCA
    
    mkdir private
    
    SAN="[SAN]\nsubjectAltName=DNS:*.$region_suffix"
    subj="/C=CN/ST=NT/L=NT/O=LIVERAMP-CN/OU=TS/CN=$region_suffix"
    
    echo "生成CA根证书"
    openssl genrsa -des3 -passout pass:$pass -out private/cakey.pem 2048
    openssl req -sha256 -new -nodes -key private/cakey.pem -passin pass:$pass \
      -x509 -days 3650 -out cacert.pem -subj "$subj"
    
    cd ..
    
    echo "生成中间CA证书"
    openssl genrsa -des3 -passout pass:$pass -out $region.key 2048
    
    openssl req -new -key $region.key \
      -passin pass:$pass \
      -subj "$subj" -reqexts SAN \
      -config <(cat openssl.cnf \
        <(printf "$SAN")) \
      -out $region.csr
    
    echo "移除密码"
    cp $region.key $region.key.org
    openssl rsa -passin pass:$pass -in $region.key.org -out $region.key
    
    echo "生成x509 crt证书"
    openssl x509 -req \
      -days 36500 \
      -in $region.csr \
      -signkey $region.key \
      -out $region.crt \
      -extensions SAN \
      -extfile <(cat openssl.cnf <(printf "$SAN"))
    
    echo "查看crt证书"
    openssl x509 -text -in $region.crt
    echo "生成pkcs12"
    openssl pkcs12 -passout pass:$pass -export -in $region.crt -inkey $region.key -out $region.p12 -CAfile $region.crt
    echo "生成JKS"
    keytool -importkeystore -v -srckeystore $region.p12 -srcstoretype pkcs12 -srcstorepass $pass -destkeystore $region.jks -deststoretype pkcs12 -deststorepass $pass
    gen.sh
    HOME            = .
    oid_section     = new_oids
    [ new_oids ]
    tsa_policy1 = 1.2.3.4.1
    tsa_policy2 = 1.2.3.4.5.6
    tsa_policy3 = 1.2.3.4.5.7
    
    [ ca ]
    default_ca  = CA_default        
    
    [ CA_default ]
    dir     = ./demoCA      
    certs       = $dir/certs        
    crl_dir     = $dir/crl      
    database    = $dir/index.txt
    new_certs_dir   = $dir/newcerts
    certificate = $dir/cacert.pem   
    serial      = $dir/serial       
    crlnumber   = $dir/crlnumber
    crl     = $dir/crl.pem      
    private_key = $dir/private/cakey.pem
    x509_extensions = usr_cert
    name_opt    = ca_default        
    cert_opt    = ca_default
    default_days    = 365           
    default_crl_days= 30            
    default_md  = default       
    preserve    = no
    policy      = policy_match
    
    [ policy_match ]
    countryName     = match
    stateOrProvinceName = match
    organizationName    = match
    organizationalUnitName  = optional
    commonName      = supplied
    emailAddress        = optional
    
    [ policy_anything ]
    countryName     = optional
    stateOrProvinceName = optional
    localityName        = optional
    organizationName    = optional
    organizationalUnitName  = optional
    commonName      = supplied
    emailAddress        = optional
    
    [ req ]
    default_bits        = 2048
    default_keyfile     = privkey.pem
    distinguished_name  = req_distinguished_name
    attributes      = req_attributes
    x509_extensions = v3_ca
    string_mask = utf8only
    
    [ req_distinguished_name ]
    countryName         = Country Name (2 letter code)
    countryName_default     = AU
    countryName_min         = 2
    countryName_max         = 2
    stateOrProvinceName     = State or Province Name (full name)
    stateOrProvinceName_default = Some-State
    localityName            = Locality Name (eg, city)
    0.organizationName      = Organization Name (eg, company)
    0.organizationName_default  = Internet Widgits Pty Ltd
    organizationalUnitName      = Organizational Unit Name (eg, section)
    commonName          = Common Name (e.g. server FQDN or YOUR name)
    commonName_max          = 64
    emailAddress            = Email Address
    emailAddress_max        = 64
    
    [ req_attributes ]
    challengePassword       = A challenge password
    challengePassword_min       = 4
    challengePassword_max       = 20
    unstructuredName        = An optional company name
    
    [ usr_cert ]
    basicConstraints=CA:FALSE
    nsComment           = "OpenSSL Generated Certificate"
    subjectKeyIdentifier=hash
    authorityKeyIdentifier=keyid,issuer
    
    [ v3_req ]
    basicConstraints = CA:FALSE
    keyUsage = nonRepudiation, digitalSignature, keyEncipherment
    
    [ v3_ca ]
    subjectKeyIdentifier=hash
    authorityKeyIdentifier=keyid:always,issuer
    basicConstraints = critical,CA:true
    
    [ crl_ext ]
    authorityKeyIdentifier=keyid:always
    
    [ proxy_cert_ext ]
    basicConstraints=CA:FALSE
    nsComment           = "OpenSSL Generated Certificate"
    subjectKeyIdentifier=hash
    authorityKeyIdentifier=keyid,issuer
    proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
    
    [ tsa ]
    default_tsa = tsa_config1   
    
    [ tsa_config1 ]
    dir     = ./demoCA      
    serial      = $dir/tsaserial    
    crypto_device   = builtin       
    signer_cert = $dir/tsacert.pem
    certs       = $dir/cacert.pem
    signer_key  = $dir/private/tsakey.pem 
    signer_digest  = sha256         
    default_policy  = tsa_policy1
    other_policies  = tsa_policy2, tsa_policy3  
    digests     = sha1, sha256, sha384, sha512  
    accuracy    = secs:1, millisecs:500, microsecs:100  
    clock_precision_digits  = 0 
    ordering        = yes
    tsa_name        = yes
    ess_cert_id_chain   = no
    ess_cert_id_alg     = sha1
    openssl.cnf

      配置完这些,顺利的话可以在 http://localhost:8888/cas/sp/metadata 看到sp的元数据。 然后将这个元数据提供给IDP。

     接下来在cas登录的时候, 应该可以从右侧看到IDP的名字,点一下试试能不能登录。如果不能的话, 说明配置还有一些问题。

      3. 属性释放 Attribute Release (IDP需要配置),这个是为了本地测试配置的, 实际上如果IDP那边配置好了,是不用管这个的

      作为IDP,当有SP登录成功时, 你需要确定将登录者的哪些属性给到SP, 可以配置services/xx.json 添加以下配置:

    复制代码
     "attributeReleasePolicy": {
            "@class": "org.apereo.cas.support.saml.services.PatternMatchingEntityIdAttributeReleasePolicy",
            "allowedAttributes" : [ "java.util.ArrayList", [ "cn","sn","email","firstName","lastName"]],
            "fullMatch" : "true",
            "reverseMatch" : "false",
            "entityIds" : ".+"
      }
    复制代码

     

    4. 属性请求(SP需要配置)

      当SP向IDP请求登录时, 希望IDP返回登录者的一些信息比如email之类的。 配置cas.properties

    复制代码
        cas.authn.pac4j.saml[0].attribute-consuming-service-index=0
        cas.authn.pac4j.saml[0].requested-attributes[0].name=FirstName
        cas.authn.pac4j.saml[0].requested-attributes[0].nameFormat=urn:oasis:names:tc:SAML:2.0:attrname-format:basic
        cas.authn.pac4j.saml[0].requested-attributes[1].name=LastName
        cas.authn.pac4j.saml[0].requested-attributes[1].nameFormat=urn:oasis:names:tc:SAML:2.0:attrname-format:basic
        cas.authn.pac4j.saml[0].requested-attributes[2].name=email
        cas.authn.pac4j.saml[0].requested-attributes[2].nameFormat=urn:oasis:names:tc:SAML:2.0:attrname-format:basic
        #eduPersonNickname urn:oid:2.16.840.1.113730.3.1.241
        #cas.authn.pac4j.saml[0].requested-attributes[3].name=urn:oid:2.16.840.1.113730.3.1.241
        #cas.authn.pac4j.saml[0].requested-attributes[3].nameFormat=urn:oasis:names:tc:SAML:2.0:attrname-format:uri
        #cas.authn.pac4j.saml[0].requested-attributes[3].friendlyName=displayName
        #cas.authn.pac4j.saml[0].requested-attributes[4].name=cn
        #cas.authn.pac4j.saml[0].requested-attributes[4].nameFormat=urn:oasis:names:tc:SAML:2.0:attrname-format:uri
        #cas.authn.pac4j.saml[0].requested-attributes[4].friendlyName=cn
    复制代码
  • 相关阅读:
    前端知识复习
    网上花店网页代码 html静态花店网页设计制作 dw静态鲜花网页成品模板素材网页 web前端网页设计与制作 div静态网页设计
    js 获取字符串中某字符出现的次数
    特斯拉自动驾驶(FSD系统)简介
    如何理解某一个开发框架的意图,从而去写和落代码文件位置不会出错
    jvm调优【减少GC频率和Full GC次数】中Gc是什么
    设计模式5、原型模式 Prototype
    Spring Boot事件监听机制:原理、实践与优化之道
    配电站房门禁监控、气体监测、视频监控系统 设备安装
    字节面试官:“这92道 Spring Boot 面试题都答不上来?”
  • 原文地址:https://www.cnblogs.com/b-gao/p/17234023.html