Чтение имени пользователя из билета Kerberos в заголовке авторизации

Я хочу прочитать имя пользователя из билета Kerberos в заголовке HTTP авторизации. Я использую Java.

Я потратил дни, пытаясь достичь этого, прочитав кучу сайтов по этому вопросу, но не смог этого сделать. Kerberos для меня новый/иностранный.

вот чего я достиг:

  • когда пользователь впервые обращается к сайту-без заголовка авторизации, сервер отвечает заголовком 401 + : WWW-аутентификация=согласование.
  • все виды волшебных вещей происходят на стороне клиента.
  • пользователь возвращается с HTTP-запросом, который содержит заголовок авторизации со значением типа: "Negotiate YHcGB...== "
  • Декодируйте кодированный base64 билет в массив байтов.

отсюда это ужасающее путешествие через неизвестное. Насколько я могу судить, следующие шаги должны быть:

  • войдите в AD / Kerberos / Server с пользователем.
  • расшифровать авиабилет.

вот что у меня есть:

логин.conf

 ServicePrincipalLoginContext
{
      com.sun.security.auth.module.Krb5LoginModule 
      required 
      principal="HTTP/some.server.com@MY.DOMAIN.COM" 
      doNotPrompt=true
      useTicketCache=true
      password=mYpasSword
      debug=true;
};

JavaClass.java

String encodedTicket = authorization.substring("Negotiate ".length());
byte[] ticket = Base64.decode(encodedTicket);       

LoginContext lc = new LoginContext("ServicePrincipalLoginContext");
lc.login();
Subject serviceSubject = lc.getSubject();
Subject.doAs(serviceSubject, new ServiceTicketDecoder(ticket));

ServiceTicketDecoder.java

public String run() throws Exception {
    Oid kerberos5Oid = new Oid("1.2.840.113554.1.2.2");

    GSSManager gssManager = GSSManager.getInstance();

    String service = "krbtgt/MY.DOMAIN.COM@MY.DOMAIN.COM";
    GSSName serviceName = gssManager.createName(service, GSSName.NT_USER_NAME);

    GSSCredential serviceCredentials = gssManager.createCredential(serviceName, GSSCredential.INDEFINITE_LIFETIME, kerberos5Oid, GSSCredential.ACCEPT_ONLY);

    GSSContext gssContext = gssManager.createContext(serviceCredentials);
    gssContext.acceptSecContext(this.serviceTicket, 0, this.serviceTicket.length);

    GSSName srcName = gssContext.getSrcName();
    return srcName.toString;
}

вход в JavaClass.java работает нормально, поэтому я предполагаю логин.conf-это хорошо. На "GSSCredential serviceCredentials = gssManager.createCredential(...- в Сервисетиккетдекодере.java возникает следующее исключение:

java.security.PrivilegedActionException: GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos Key)

Я не уверен, что это правильный подход. Я также не знаю, каким должно быть значение "String service" или как получить эту информацию. Вы можете мне помочь?


изменить: авторизоваться.conf

 ServicePrincipalLoginContext
{
      com.sun.security.auth.module.Krb5LoginModule 
      required 
      principal="HTTP/some.server.com@MY.DOMAIN.COM" 
      doNotPrompt=true
      useTicketCache=true
      keyTab="C:/server-http.keytab" 
      debug=true;
};

я получил файл keytab. По-видимому, HTTP / некоторые.сервер.учетная запись пользователя com уже была учетной записью участника-службы. Теперь у меня проблема с JavaClass.java в lc.login ():

javax.security.auth.login.LoginException: KDC has no support for encryption type (14)
Caused by: KrbException: KDC has no support for encryption type (14)
Caused by: KrbException: Identifier doesn't match expected value (906)

файл keytab зашифрован с помощью des-cbc-md5, и у меня есть следующее определено в krb.файл conf:

[libdefaults]
default_realm = MY.DOMAIN.COM
default_tkt_enctypes = des-cbc-md5
default_tgs_enctypes = des-cbc-md5

если я изменю enctypes по умолчанию на, например, aes128-cts, я получу следующее исключение:

javax.security.auth.login.LoginException: Do not have keys of types listed in default_tkt_enctypes available; only have keys of following type: DES CBC mode with MD5

Я не понимаю, что случилось...

2 ответов


Kerberos-это доверенная третья сторона система безопасности: маркер безопасности, который вы получаете от клиента, расшифровывается только вами и без обращения к серверам инфраструктуры Kerberos (таким как KDC). Вы на правильном пути; однако, похоже, вам не хватает этого фрагмента знаний Kerberos, чтобы направлять вас в ваших дальнейших исследованиях.

способ, которым это достигается, заключается в том, что на сервере вам нужно keytab файл, содержащий ваш секретный ключ сервера. Сервер Kerberos (Microsoft Windows Server, я полагаю) должен иметь учетная запись участника службы создан для вашего сервиса. Администратор может предоставить вам файл keytab, созданный для этой учетной записи, который будет содержать секретный ключ.

затем вам нужно настроить сервер для поиска этого файла keytab; он используется на серверном шаге с участием LoginContext.login. Ваш код, который принимает контекст безопасности, должен выполняться внутри doPrivileged код сегмент, в котором действуют учетные данные на стороне сервера.


Если все, что вам нужно, это имя пользователя, есть более простой способ.

request.getUserPrincipal().getName()

http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getUserPrincipal() http://docs.oracle.com/javase/7/docs/api/java/security/Principal.html