如何在基于Java的自定义web服务器中集成windows身份验证(SSO)?

如何在基于Java的自定义web服务器中集成windows身份验证(SSO)?,java,webserver,single-sign-on,kerberos,jaas,Java,Webserver,Single Sign On,Kerberos,Jaas,我有一个基于Java的自定义web服务器应用程序,我需要支持单点登录。 我对这个问题进行了研究,发现我可以使用JAAS实现SSO。我已经将http服务器配置为接受身份验证握手过程,因此我将登录用户身份验证编码到java应用程序中,并将JAAS身份验证功能传递给它。 现在,我需要使用我的域控制器对用户进行身份验证。因此,我使用jaas.conf文件来定义LoginModule: SSOAUTH { com.sun.security.auth.module.Krb5LoginModule req

我有一个基于Java的自定义web服务器应用程序,我需要支持单点登录。 我对这个问题进行了研究,发现我可以使用JAAS实现SSO。我已经将http服务器配置为接受身份验证握手过程,因此我将登录用户身份验证编码到java应用程序中,并将JAAS身份验证功能传递给它。
现在,我需要使用我的域控制器对用户进行身份验证。因此,我使用jaas.conf文件来定义LoginModule:

SSOAUTH {
  com.sun.security.auth.module.Krb5LoginModule required  
  useKeyTab=false
  storeKey=true
  useTicketCache=false
  debug=true;
};
如您所见,我希望使用Kerberos协议。
第一个问题是:我是否需要为我的域控制器进行一些安装/配置以支持此协议?

这是我的web服务器应用程序中的java代码,它将使用JAAS处理整个身份验证过程:

public class LDAPClient
{
   private static final String LOGIN_MODULE_NAME = "SSOAUTH";


/**
 * Constructor
 * @param domain
 * @param ldapServer
 * @param jaasConfigPath
 */
public LDAPClient(String domain, String ldapServer, String jaasConfigPath)
{
    System.setProperty("sun.security.krb5.debug", "true");
    System.setProperty("java.security.krb5.realm", domain);
    System.setProperty("java.security.krb5.kdc", ldapServer); // LDAP active directory server name
    System.setProperty("javax.security.auth.useSubjectCredsOnly", "true");
    System.setProperty("java.security.auth.login.config", jaasConfigPath); // path to the jaas.conf file.
}


/**
 * Authenticates the given kerberos token and returns the client principal.
 *
 * @param argKerberosTokenAsBase64 The kerberos content token.
 * @return
 * @throws Exception
 */
public String authenticate(String argKerberosTokenAsBase64) throws Exception
{
    BASE64Decoder decoder = new BASE64Decoder();
    byte[] kerberosToken = decoder.decodeBuffer(argKerberosTokenAsBase64.substring("Negotiate ".length()));
    String clientName;

    try
    {
        // Login to the KDC and obtain subject for the service principal
        Subject subject = createServiceSubject(argKerberosTokenAsBase64);
        if (subject != null)
        {
            clientName = acceptSecurityContext(subject, kerberosToken).toUpperCase();
            System.out.println("Security context successfully initialized!");
        }
        else
        {
            throw new Exception("Unable to obtain kerberos service context");
        }
    }
    catch (Throwable throwable)
    {
        System.out.println("Token: " + argKerberosTokenAsBase64);
        throwable.printStackTrace();
        throw new Exception(throwable);
    }

    return clientName;
}

/**
 * Creates service subject based on the service principal and service
 * password.
 *
 * @param password
 * @return
 * @throws LoginException
 */
private static Subject createServiceSubject(String password)
        throws LoginException
{
    // "Client" references the JAAS configuration in the jaas.conf file.
    LoginContext loginCtx = new LoginContext(LOGIN_MODULE_NAME, new LoginCallbackHandler(password));
    loginCtx.login();
    return loginCtx.getSubject();
}

/**
 * Completes the security context initialisation and returns the client
 * name.
 * @param argSubject
 * @param serviceTicket
 * @return
 * @throws GSSException
 */
private static String acceptSecurityContext(Subject argSubject, final byte[] serviceTicket) throws GSSException
{
    // Accept the context and return the client principal name.
    return (String) Subject.doAs(argSubject, new PrivilegedAction()
    {
        public Object run()
        {
            try
            {
                // Identify the server that communications are being made
                // to.
                GSSManager manager = GSSManager.getInstance();
                GSSContext context = manager.createContext((GSSCredential) null);
                context.acceptSecContext(serviceTicket, 0, serviceTicket.length);
                return context.getSrcName().toString();
            }
            catch (GSSException exp)
            {
                throw new RuntimeException(exp);
            }
        }
    });
}
}


我有以下LoginException:javax.security.auth.login.LoginException:预验证信息无效(24)

我正在将kerberos身份验证令牌传递给LoginContext,请参阅对createServiceSubject()的调用,以便获取主题,是正确的还是我在这里遗漏了什么?

这是System.out调试错误的部分:

>>>KRBError:
 sTime is Wed Feb 12 14:29:17 IST 2014 1392208157000
 suSec is 301542
 error code is 25
 error Message is Additional pre-authentication required
 realm is DOMAIN.LOCAL
 sname is krbtgt/DOMAIN.LOCAL
 eData provided.
 msgType is 30
>>>Pre-Authentication Data:
 PA-DATA type = 19
 PA-ETYPE-INFO2 etype = 23
 PA-ETYPE-INFO2 salt = null
 salt for 3 is DOMAIN.LOCALskadar
>>>Pre-Authentication Data:
 PA-DATA type = 2
 PA-ENC-TIMESTAMP
>>>Pre-Authentication Data:
 PA-DATA type = 16
>>>Pre-Authentication Data:
 PA-DATA type = 15
AcquireTGT: PREAUTH FAILED/REQUIRED, re-send AS-REQ
Updated salt from pre-auth = DOMAIN.LOCALskadar
>>>KrbAsReq salt is DOMAIN.LOCALskadar
Pre-Authenticaton: find key for etype = 3
AS-REQ: Add PA_ENC_TIMESTAMP now
>>> EType: sun.security.krb5.internal.crypto.DesCbcMd5EType

如果您使用的是Tomcat,请使用。

您可能需要查看SPNEGO。有一个java实现,我确实研究过,但我不知道我是否可以将它用于我的自定义http服务器,因为我知道它可以用于Tomcat等知名服务器。还有一件事我忘了提到,我需要支持跨平台SSO(windows、linux等)。输入的密码不正确。在AD中创建新用户并重试。顺便问一下,你是如何把校长传给JAAS的?这可能是因为你根本没有把任何校长交给jaas。是JAAS提示的。好的,谢谢你。我查一查,你对校长的看法可能是对的。。。