У меня есть пользовательское приложение для веб-серверов на основе Java, и мне нужно поддерживать Single-Sign-On. Я провел исследование по этой проблеме и выяснил, что я могу использовать JAAS для реализации SSO. Я уже настроил свой http-сервер, чтобы принять процесс установления подлинности аутентификации, поэтому у меня есть зарегистрированная пользовательская аутентификация, закодированная в моем приложении Java, и я передаю ей мою функцию аутентификации JAAS.
Теперь мне нужно аутентифицировать пользователя с помощью моего контроллера домена. Таким образом, я использую файл jaas.conf определить LoginModule:
Как интегрировать проверку подлинности Windows (SSO) в моем пользовательском веб-сервере на основе Java?
SSOAUTH {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=false
storeKey=true
useTicketCache=false
debug=true;
};
Как вы можете видеть, что я хотел бы использовать протокол Kerberos.
Первый вопрос: должен ли я сделать некоторую установку/настройку для моего контроллера домена для поддержки этого протокола?
Это мой 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
Возможно, вы захотите посмотреть SPNEGO. Существует реализация java на http://spnego.sourceforge.net/ – Qwerky
. Я изучил это, но я не знаю, могу ли я использовать его с моим настраиваемым HTTP-сервером, потому что я знаю, что он может работать с известными серверами как Tomcat и т. д. – Snow
Еще одна вещь, о которой я забыл упомянуть, заключается в том, что мне нужно поддерживать кросс-платформу SSO (windows, linux, ...) – Snow