Redmine 的 GSSAPI 身份验证失败

GSSAPI authentication fails for Redmine

我已经使用 Kerberos + GSSAPI 在 Apache 上为 Redmine 配置了 SSO。 它第一次工作正常。但是我推迟了这个配置,当我再次设置它时 SSO 身份验证失败,httpd 错误日志中出现以下错误:

[http:trace4] [pid 29360] http_request.c(316): [client 192.168.0.10:47380]   Authorization: Negotiate TlRMTVNTUAABAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAKADk4AAAADw==
[rewrite:trace2] [pid 29360] mod_rewrite.c(470): [client 192.168.0.10:47380] 192.168.0.10 - - [redmine.mydomain.com/sid#558a80593c58][rid#558a806408f0/initial] init rewrite engine with requested uri /
[rewrite:trace1] [pid 29360] mod_rewrite.c(470): [client 192.168.0.10:47380] 192.168.0.10 - - [redmine.mydomain.com/sid#558a80593c58][rid#558a806408f0/initial] pass through /
[authz_core:debug] [pid 29360] mod_authz_core.c(809): [client 192.168.0.10:47380] AH01626: authorization result of Require valid-user : denied (no authenticated user yet)
[authz_core:debug] [pid 29360] mod_authz_core.c(809): [client 192.168.0.10:47380] AH01626: authorization result of <RequireAny>: denied (no authenticated user yet)
[auth_gssapi:debug] [pid 29360] mod_auth_gssapi.c(900): [client 192.168.0.10:47380] URI: /, no main, no prev
[auth_gssapi:error] [pid 29360] [client 192.168.0.10:47380] GSS ERROR In Negotiate Auth: gss_accept_sec_context() failed: [An unsupported mechanism was requested (Unknown error)]

我还遇到了另一个错误: [auth_gssapi:info] [pid 8012] [client 127.0.0.1:37910] NO AUTH DATA 客户端未发送任何身份验证 headers

我的krb5.conf

[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 default_realm = MYDOMAIN.COM
 default_keytab_name = /etc/krb5.keytab
 dns_lookup_realm = false
 dns_lookup_kdc = false
 ticket_lifetime = 24h
 renew_lifetime = 24h
 forwardable = true
 default_tgs_enctypes = aes256-cts-hmac-sha1-96
 default_tkt_enctypes = aes256-cts-hmac-sha1-96

[realms]
 MYDOMAIN.COM = {
  kdc = mydc.mydomain.com
  admin_server = mydc.mydomain.com
  default_domain = mydomain.com
  kpasswd_server = mydc.mydomain.com
 }

[domain_realm]
 .mydomain.com = MYDOMAIN.COM
 mydomain.com = MYDOMAIN.COM

我的密钥表

# klist -ek /etc/krb5.keytab
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
   4 HTTPS/redmine.mydomain.com@MYDOMAIN.COM (aes256-cts-hmac-sha1-96)

Keytab 测试:

# kinit -V -kt /etc/krb5.keytab -p HTTPS/redmine.mydomain.com@MYDOMAIN.COM
Using default cache: /tmp/krb5cc_0
Using principal: HTTPS/redmine.mydomain.com@MYDOMAIN.COM
Using keytab: /etc/krb5.keytab
Authenticated to Kerberos v5
#
# klist -Af
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: HTTPS/redmine.mydomain.com@MYDOMAIN.COM

Valid starting       Expires              Service principal
02/15/2019 16:31:47  02/16/2019 02:31:47  krbtgt/MYDOMAIN.COM@MYDOMAIN.COM
        renew until 02/16/2019 16:31:47, Flags: FPRIA

我的密钥表是通过以下命令生成的:

ktpass -princ HTTPS/redmine.mydomain.com@MYDOMAIN.COM -mapuser serviceuser -pass my_password -ptype KRB5_NT_PRINCIPAL -crypto AES256-SHA1 -out redmine.keytab -mapOp set

SPN 信息

C:\>setspn -L serviceuser
Registered ServicePrincipalNames for CN=serviceuser,OU=Pseudo Accounts,OU=Managed Objects,DC=mydomain,DC=com:
        HTTPS/redmine.mydomain.com

C:\>setspn -Q HTTPS/redmine.mydomain.com
Checking domain DC=mydomain,DC=com
CN=serviceuser,OU=Pseudo Accounts,OU=Managed Objects,DC=mydomain,DC=com
        HTTPS/redmine.mydomain.com

Existing SPN found!

看起来我的密钥表没问题。

我的 redmine.conf for Apache

<VirtualHost *:80>
    ServerAdmin admin@mydomain.com
    ServerName redmine.mydomain.com
    Redirect "/" "https://redmine.mydomain.com/"
</VirtualHost>

<VirtualHost *:443>
    ServerAdmin admin@mydomain.com
    ServerName redmine.mydomain.com
    DocumentRoot /var/www/redmine/public/


    # SSL
    # Enable SSL with Perfect Forward Secrecy
    SSLEngine on
    SSLProtocol +TLSv1.2 +TLSv1.1 +TLSv1
    SSLCompression off
    SSLCertificateFile /etc/ssl/certs/mydomain.com.crt
    SSLCertificateKeyFile /etc/ssl/private/mydomain.com.key

    ## Passenger Configuration

    RailsBaseURI /
    PassengerAppRoot /var/www/redmine
    PassengerRuby /usr/local/rvm/gems/ruby-2.4.4/wrappers/ruby
    PassengerFriendlyErrorPages on
    RailsSpawnMethod smart
    RailsAppSpawnerIdleTime 3600
    PassengerMaxPreloaderIdleTime 0
    PassengerMaxRequests 5000

    PassengerUser apache
    PassengerGroup apache

    <Directory /var/www/redmine/public>
            Options +Indexes +FollowSymLinks -MultiViews
            AllowOverride All
            <IfVersion < 2.3 >
                    Order allow,deny
                    Allow from all
            </IfVersion>
            <IfVersion >= 2.3>
                    Require all granted
            </IfVersion>
    </Directory>

    # SSO start 

    <Location "/">
        RewriteEngine     On
        RewriteCond       %{IS_SUBREQ} ^false$
        RewriteCond       %{LA-U:REMOTE_USER} (.+)
        RewriteRule       . - [E=RU:%1]
        RequestHeader     add REMOTE_USER %{RU}e

        SSLRequireSSL
        AuthType GSSAPI
        AuthName "login:"
        GssapiSSLonly On
        GssapiAllowedMech krb5
        GssapiCredStore keytab:/etc/krb5.keytab
        GssapiLocalName On
        GssapiBasicAuth On

        Require valid-user
    </Location>

    # SSO end   

    #AddOutputFilter DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/javascript text/css

    #BrowserMatch ^Mozilla/4 gzip-only-text/html
    #BrowserMatch ^Mozilla/4.0[678] no-gzip
    #BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

    ErrorLog /var/log/httpd/redmine.error.log
    LogLevel trace8
    CustomLog /var/log/httpd/redmine.access.log combined
    ServerSignature Off

</VirtualHost>

我也试过没有 GssapiAllowedMech krb5 选项,但我得到了同样的错误。

我修改了redmine app app/controllers/application_controller.rb。将以下字符串添加到 find_current_user 函数:

elsif (forwarded_user = request.env["REMOTE_USER"])
    # web server authentication
    user = (User.find_by_login(forwarded_user) rescue nil)

结果:

  def find_current_user
    user = nil
    unless api_request?
      if session[:user_id]
        # existing session
        user = (User.active.find(session[:user_id]) rescue nil)
      # Start custom settings
      elsif (forwarded_user = request.env["REMOTE_USER"])
        # web server authentication
        user = (User.find_by_login(forwarded_user) rescue nil)
      # End custom settings
      elsif autologin_user = try_to_autologin
        user = autologin_user
      elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth?
        # RSS key authentication does not start a session
        user = User.find_by_rss_key(params[:key])
      end
    end

浏览器配置。
对于 Google Chrome、Edge、Opera,我在 Internet 选项中设置了本地 Intranet 和受信任的站点区域,以使用当前用户名和密码自动登录。
对于 FF:

network.negotiate-auth.delegation-uris = mydomain.com
network.negotiate-auth.trusted-uris = mydomain.com

有什么想法吗?

我通过为我的服务用户添加 HTTP 主体并使用 HTTP 和 HTTPS 主体重新创建密钥表来解决我的问题。

C:\>setspn -L serviceuser
Registered ServicePrincipalNames for CN=serviceuser,OU=Pseudo Accounts,OU=Managed Objects,DC=mydomain,DC=com:
        HTTP/redmine.mydomain.com
        HTTPS/redmine.mydomain.com

C:\>setspn -Q HTTP/redmine.mydomain.com
Checking domain DC=mydomain,DC=com
CN=serviceuser,OU=Pseudo Accounts,OU=Managed Objects,DC=mydomain,DC=com
        HTTP/redmine.mydomain.com
        HTTPS/redmine.mydomain.com

Existing SPN found!

然后分两步创建密钥表:

ktpass -princ HTTP/redmine.mydomain.com@MYDOMAIN.COM -mapuser serviceuser -pass password -ptype KRB5_NT_PRINCIPAL -crypto All -out HTTP_redmine.keytab -mapOp set 

ktpass -princ HTTPS/redmine.mydomain.com@MYDOMAIN.COM -mapuser serviceuser -pass password -ptype KRB5_NT_PRINCIPAL -crypto All -in HTTP_redmine.keytab -out HTTPS_redmine.keytab -mapOp set

在第二步中,我从第一步中导入了带有 HTTP SPN 的密钥选项卡。