Browsers keeps sending NTLM token instead of Kerberos - How to solve it?

[亡魂溺海] 提交于 2019-12-18 09:36:40

问题


I can't seem to correctly configure the system and have the browser send a kerberos ticket to the web-server. Instead, a NTLM token is sent.

Q: How can I solve this?

All details and configurations are listed below.


Infrastructure:

I have three machines within the domain COMPANY.local:

  • PC-I7.COMPANY.local (on 192.168.0.5). It acts as KDC, it's an Active-Directory server with the other machines (see below) registered in the AD. Also has the DNS for the local network configured. The domain in the Active Directory is: COMPANY.local
  • SOFTWARE.COMPANY.local (on 192.168.0.10) runs the jetty web-application which has the Jetty/SPNego support configured.
  • OTHER.COMPANY.local (on 192.168.0.9), just a client so I can access the software server from another machine.

The last two are actually VMs running on a linux server in the intranet. They are reachable with their own IP. Their primary DNS in Network Configuration points to 192.168.0.5.

Both are joined in COMPANY.local and are present as computers in the AD.

I know client and server should stay on different machines; and being them onto two different VM's should avoid this issue.

All three machines are registered as A hosts in the DNS with a reverse pointer for each of them in the Reverse lookup zone.


SPN

After having created the user software in the Active Directory, I generate the keytab file

ktpass -princ HTTP/software.company.local@COMPANY.LOCAL -mapuser software@COMPANY.LOCAL -crypto ALL -ptype KRB5_NT_PRINCIPAL -pass __PassForADUserSoftware__ -out C:/winnt/krb5.keytab

I get the following output which seems to contain an error:

Targeting domain controller: PC-I7.COMPANY.local
  Failed to set property 'userPrincipalName' to 'HTTP/software.company.local@COMPANY.LOCAL' on Dn 'CN=Software SSO Kerberized WebServer,DC=COMPANY,DC=local': 0x13.
  WARNING: Failed to set UPN HTTP/software.company.local@COMPANY.LOCAL on CN=Software SSO Kerberized WebServer,DC=COMPANY,DC=local.
  kinits to 'HTTP/software.company.local@COMPANY.LOCAL' will fail.
Successfully mapped HTTP/software.company.local to software.
Password successfully set!
Key created.
Key created.
Key created.
Key created.
Key created.
Output keytab to C:/winnt/krb5.keytab:
Keytab version: 0x502 
keysize 64 HTTP/software.company.local@COMPANY.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 8 etype 0x1 (DES-CBC-CRC) keylength 8 (0x0bf1688040abadba)
keysize 64 HTTP/software.company.local@COMPANY.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 8 etype 0x3 (DES-CBC-MD5) keylength 8 (0x0bf1688040abadba)
keysize 72 HTTP/software.company.local@COMPANY.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 8 etype 0x17 (RC4-HMAC) keylength 16 (0x737d9811dd38e108741461ba79153192)
keysize 88 HTTP/software.company.local@COMPANY.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 8 etype 0x12 (AES256-SHA1) keylength 32 (0xcc8ab2939f822f9df6904a987954e0cfaa261bc36803af6c5f8d9a98f1d4f2aa)
keysize 72 HTTP/software.company.local@COMPANY.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 8 etype 0x11 (AES128-SHA1) keylength 16 (0xd616b814dcd1b955f125ab4de5895d39)

The AD user has the two This account supports the Kerbers AES-... checkboxes checked.


The OTHER.COMPANY.local server

I login to this machine via RDP with the credentials:

user: Administrator
pass: ARandomPass

When asking for a ticket from OTHER server with

kinit HTTP/software.company.local@COMPANY.LOCAL

I can see this packets with wireshark

Internet explorer (and therefore Chrome) have the following settings in Internet Options:

Security > Local Intranet > Sites > *.company.local
Security > Custom level > Automatic logon only in Intranet area

When I reach the web application on http://software.company.local:8998/software/login

I can see the browser sends a NTLM request

and I can see the Defective Token exception on the server side

WARN:oejs.SpnegoLoginService:qtp506835709-28: 
GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
at sun.security.jgss.GSSHeader.<init>(GSSHeader.java:97)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:306)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285)
at org.eclipse.jetty.security.SpnegoLoginService.login(SpnegoLoginService.java:138)
at org.eclipse.jetty.security.authentication.LoginAuthenticator.login(LoginAuthenticator.java:61)
at org.eclipse.jetty.security.authentication.SpnegoAuthenticator.validateRequest(SpnegoAuthenticator.java:99)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:483)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
at org.eclipse.jetty.server.Server.handle(Server.java:524)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:319)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:253)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589)
at java.lang.Thread.run(Thread.java:748)

Also this info appears in the java log:

Debug is true storeKey true useTicketCache false useKeyTab true doNotPrompt false 
ticketCache is null isInitiator false 
KeyTab is C:/software/inst/modules/common-config/auth/krb5.keytab refreshKrb5Config is false 
principal is HTTP/software.company.local@COMPANY.LOCAL tryFirstPass is false 
useFirstPass is false storePass is false clearPass is false

Information I can gather from the linked answer:

  • Point 1: The SPN for the HTTP service does match the URL entered by the browser. I input software.company.local in the browser which is the same as the SPN HTTP/software.company.local@COMPANY.LOCAL

  • Point 2: *.company.local is added to the trusted sites.

  • Point 3: I'm not restricting the encrpytion to DES-CBC-MD5

  • Point 3: I have checked AES-128 and AES-256 ... but not DES because the Windows Server version I am working with has the checkbox saying Use only Kerberos DES encryption types for this account, which is not what I want. Should I check it?


The SOFTWARE.COMPANY.local server

The jetty web-application is registered as a Windows Server.

These are the configuration files:

krb5.ini file:

[libdefaults]
default_realm = COMPANY.LOCAL
permitted_enctypes = rc4-hmac,aes128-cts,aes256-cts,arcfour-hmac-md5,aes256-cts-hmac-sha1-96    
default_tgs_enctypes = rc4-hmac,aes128-cts,aes256-cts,arcfour-hmac-md5,aes256-cts-hmac-sha1-96
default_tkt_enctypes = rc4-hmac,aes128-cts,aes256-cts,arcfour-hmac-md5,aes256-cts-hmac-sha1-96
default_keytab_name = FILE:C:/software/inst/modules/common-config/krb5.keytab

[domain_realm]
COMPANY.local = COMPANY.LOCAL
.company.local = COMPANY.LOCAL

[realms]
COMPANY.LOCAL = {
    admin_server = PC-I7.COMPANY.local
    kdc = PC-I7.COMPANY.local:88
}

spnego.conf file:

com.sun.security.jgss.initiate {
    com.sun.security.auth.module.Krb5LoginModule required
    principal = "HTTP/software.company.local@COMPANY.LOCAL"
    keyTab = "C:/software/inst/modules/common-config/auth/krb5.keytab"
    useKeyTab = true
    storeKey = true
    debug = true
    isInitiator = false;
};

com.sun.security.jgss.accept {
    com.sun.security.auth.module.Krb5LoginModule required
    principal = "HTTP/software.company.local@COMPANY.LOCAL"
    useKeyTab = true
    keyTab = "C:/software/inst/modules/common-config/auth/krb5.keytab"
    storeKey=true
    debug=true
    isInitiator=false;
};

and this is the spnego.properties file:

targetName = HTTP/software.company.local

My jetty-web.xml configuration file contains:

<Get name="securityHandler">
    <Set name="loginService">
        <New class="org.eclipse.jetty.security.SpnegoLoginService">
            <Set name="name">Company Realm</Set>
            <Set name="config">
                <SystemProperty name="jetty.home" default="."/>/modules/common-config/auth/spnego.properties</Set>
        </New>
    </Set>
    <Set name="checkWelcomeFiles">true</Set>
</Get>

This is how I programmatically register the spnego configuration in Java:

private SecurityHandler wrapEnableSSOAuthHandlers(final Handler collection) {

    // ini file
    System.setProperty(
            "java.security.krb5.conf",
            _config.getString("authentication.win_sso.spnego.krb5") // the krb5.ini file
    );
    System.setProperty(
            "java.security.auth.login.config",
            _config.getString("authentication.win_sso.spnego.login") // the spnego.conf file
    );
    System.setProperty(
            "javax.security.auth.useSubjectCredsOnly",
            "false"
    );

    final Constraint spnegoConstraint = new Constraint();
    spnegoConstraint.setName(Constraint.__SPNEGO_AUTH);

    final String domainRealm = _config.getString("authentication.win_sso.domain.realm");    // resolves to COMPANY.LOCAL

    spnegoConstraint.setRoles(new String[]{domainRealm});
    spnegoConstraint.setAuthenticate(true);

    final ConstraintMapping mapping = new ConstraintMapping();
    mapping.setConstraint(spnegoConstraint);
    mapping.setPathSpec("/*");

    final String spnegoProperties = _config.getString("authentication.win_sso.spnego.properties");      // the spnego.properties file

    final SpnegoLoginService loginService = new SpnegoLoginService();
    loginService.setConfig(spnegoProperties);
    loginService.setName(domainRealm);

    final ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler();
    securityHandler.setLoginService(loginService);
    securityHandler.setConstraintMappings(new ConstraintMapping[]{mapping});
    securityHandler.setRealmName(domainRealm);
    securityHandler.setAuthenticator(new SpnegoAuthenticator());
    securityHandler.setHandler(collection);
    return securityHandler;
}

and

// here I disable the TRACE method for all calls 
Handler wrappedSecurityHandler = wrapDisableTraceHandlers(handlers);
wrappedSecurityHandler = wrapEnableSSOAuthHandlers(wrappedSecurityHandler);
_server.setHandler(wrappedSecurityHandler);

EDIT 1: Additional info

I have downloaded the Kerberos Authentication Tester Tool and when running it from the KDC server (192.168.0.5) and testing against http://software.company.local:8998 it shows a correct Kerberos authentication.

When running it from the 192.168.0.10 server (where the browser is) it says:

Unexpected authorization header

and authentication method: NTLM.

I guess it's either a DNS issue or the fact that they are two VM on the same server.


回答1:


Apparently, having client and server on two distinct virtual machines ( that are on the same physical server! ) can lead to a NTLM token.

I thought VM's would dodge the client-and-server-on-the-same-machine-issue.

So, if you

  • like me, are testing with VM's residing on the same physical machine, and
  • have set everything right but still getting a Defective token detected,

you should try to access the server from a different computer (as long as that machine is joined to the company domain).



来源:https://stackoverflow.com/questions/51082273/browsers-keeps-sending-ntlm-token-instead-of-kerberos-how-to-solve-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!