Въведение в SPNEGO / Kerberos удостоверяване през пролетта

1. Общ преглед

В този урок ще разберем основите на протокола за удостоверяване на Kerberos. Също така ще разгледаме нуждата от SPNEGO във връзка с Kerberos.

И накрая, ще видим как да използваме разширението Spring Security Kerberos за създаване на приложения, активирани за Kerberos с SPNEGO.

Преди да продължим, струва си да отбележим, че този урок ще въведе много нови термини за непосветените в тази област. Следователно ще прекараме известно време отпред, за да покрием основанията.

2. Разбиране на Kerberos

Kerberos е мрежов протокол за удостоверяване, разработен в Масачузетския технологичен институт (MIT) в началото на осемдесетте години. Както разбирате, това е относително старо и издържа изпитанието на времето. Windows Server широко поддържа Kerberos като механизъм за удостоверяване и дори го е направил опцията за удостоверяване по подразбиране.

Технически, Kerberos е протокол за удостоверяване, базиран на билети, който позволява на възлите в компютърната мрежа да се идентифицират помежду си.

2.1. Калъф за проста употреба за Kerberos

Нека изготвим хипотетична ситуация, за да докажем това.

Да предположим, че потребителят, чрез своя пощенски клиент на своята машина, трябва да изтегли имейлите си от пощенски сървър на друга машина в същата мрежа. Тук има очевидна необходимост от удостоверяване. Пощенският клиент и пощенският сървър трябва да могат да се идентифицират и да си имат доверие, за да комуникират сигурно.

Как може Kerberos да ни помогне тук? Kerberos представя трета страна, наречена Key Distribution Center (KDC) , която има взаимно доверие с всеки възел в мрежата. Нека да видим как това може да работи в нашия случай:

2.2. Основни аспекти на протокола Kerberos

Макар това да звучи езотерично, това е доста просто и креативно при осигуряването на комуникация през незащитена мрежа. Някои от проблемите, представени тук, се приемат за даденост в ерата на TLS навсякъде!

Въпреки че тук не е възможно подробно обсъждане на протокола Kerberos, нека да разгледаме някои важни аспекти:

  • Предполага се, че доверието между възлите (клиент и сървър) и KDC съществува в същото царство
  • Паролата никога не се обменя по мрежата
  • Доверието между клиента и сървъра се подразбира въз основа на факта, че те могат да дешифрират съобщения с ключ, споделен само с KDC
  • Доверието между клиента и сървъра е взаимно
  • Клиентът може да кешира билети за многократна употреба до изтичане на срока, осигурявайки еднократно изписване
  • Съобщенията за удостоверяване се основават на клеймото за време и следователно са добри само за еднократна употреба
  • И трите страни тук трябва да имат относително синхронизирано време

Макар че това просто надрасква повърхността на този красив протокол за удостоверяване, достатъчно е да започнем с нашия урок.

3. Разбиране на SPNEGO

SPNEGO означава съкратен и защитен механизъм за преговори GSS-API. Доста име! Нека първо видим какво означава GSS-API. Интерфейсът на приложната програма за обща услуга за сигурност (GSS-API) не е нищо друго освен IETF стандарт за клиент и сървър, за да комуникират по сигурен и агностичен начин от доставчика.

SPNEGO е част от GSS-API за клиент и сървър за договаряне на избора на защитен механизъм, който да се използва, например, Kerberos или NTLM.

4. Защо се нуждаем от SPNEGO с Kerberos?

Както видяхме в предишния раздел, Kerberos е чист протокол за мрежово удостоверяване, работещ предимно в транспортния слой (TCP / UDP). Въпреки че това е добре за много случаи на употреба, това не отговаря на изискванията за съвременната мрежа. Ако имаме приложение, което работи с по-висока абстракция, като HTTP, не е възможно да използваме Kerberos директно.

Тук SPNEGO ни идва на помощ. В случай на уеб приложение, комуникацията се осъществява предимно между уеб браузър като Chrome и уеб сървър като Tomcat, който хоства уеб приложението през HTTP. Ако е разрешено, те могат да договарят Kerberos като механизъм за сигурност чрез SPNEGO и да обменят билети като SPNEGO токени през HTTP .

И така, как това променя нашия сценарий, споменат по-рано? Нека заменим нашия прост пощенски клиент с уеб браузър и пощенски сървър с уеб приложение:

Така че в това не се е променило много в сравнение с предишната ни диаграма, с изключение на това, че комуникацията между клиент и сървър се осъществява изрично през HTTP сега. Нека разберем това по-добре:

  • Клиентската машина се удостоверява срещу KDC и кешира TGT
  • Уеб браузърът на клиентската машина е конфигуриран да използва SPNEGO и Kerberos
  • Уеб приложението също е конфигурирано да поддържа SPNEGO и Kerberos
  • Уеб приложението отправя предизвикателство „Договаряне“ към уеб браузъра, който се опитва да получи достъп до защитен ресурс
  • Сервизният билет е опакован като SPNEGO маркер и се обменя като HTTP заглавка

5. Изисквания

Преди да можем да продължим да разработваме уеб приложение, което поддържа режим на удостоверяване Kerberos, трябва да съберем някои основни настройки. Нека преминем бързо през тези задачи.

5.1. Настройване на KDC

Настройването на среда на Kerberos за производствена употреба е извън обхвата на този урок. За съжаление това не е маловажна задача и също е крехка. Има няколко опции, за да получите внедряване на Kerberos, както с отворен код, така и с търговски версии:

  • MIT прави внедряването на Kerberos v5 достъпно за множество операционни системи
  • Apache Kerby е разширение на Apache Directory, което осигурява свързване на Java Kerberos
  • Windows Server от Microsoft поддържа Kerberos v5, първоначално подкрепен от Active Directory
  • Heimdel има реализация на Kerberos v5

The actual set-up of KDC and related infrastructure is dependent on the provider and should be followed from their respective documentation. However, Apache Kerby can be run inside a Docker container, which makes it platform-neutral.

5.2. Setting up Users in KDC

We need to set up two users — or, as they call it, principals — in KDC. We can use the “kadmin” command-line tool for this purpose. Let's suppose we've created a realm called “baeldung.com” in the KDC database and logged in to “kadmin” with a user having admin privileges.

We'll create our first user, whom we wish to authenticate from a web browser, with:

$ kadmin: addprinc -randkey kchandrakant -pw password Principal "[email protected]" created.

We'll also need to register our web application with the KDC:

$ kadmin: addprinc -randkey HTTP/[email protected] -pw password Principal "HTTP/[email protected]" created.

Note the convention for naming the principal here, as this must match the domain on which the application is accessible from the web browser. The web browser automatically tries to create a Service Principal Name (SPN) with this convention when presented with a “Negotiate” challenge.

We also need to export this as a keytab file to make it available to the web application:

$ kadmin: ktadd -k baeldung.keytab HTTP/[email protected]

This should give us a file named “baeldung.keytab”.

5.3. Browser Configuration

We need to enable the web browser that we use to access a protected resource on the web application for the “Negotiate” authentication scheme. Fortunately, most of the modern web browsers like Chrome support “Negotiate” as an authentication scheme by default.

Additionally, we can configure the browser to provide “Integrated Authentication”. In this mode, when presented with the “Negotiate” challenge, the browser tries to make use of the cached credentials in the host machine, which has already been logged into a KDC principal. However, we'll not use this mode in here to keep things explicit.

5.4. Domain Configuration

It is understandable that we may not have actual domains to test our web application. But sadly, we can't use localhost or 127.0.0.1 or any other IP address with Kerberos authentication. There is, however, an easy solution to this, which involves setting up entries in the “hosts” file like:

demo.kerberos.bealdung.com 127.0.0.1

6. Spring to Our Rescue!

Finally, as we've got the basics clear, it is time to test the theory. But, won't it be cumbersome to create a web application supporting SPNEGO and Kerberos? Not if we use Spring. Spring has a Kerberos Extension as part of Spring Security that supports SPNEGO with Kerberos seamlessly.

Almost all we have to do is just configurations in Spring Security to enable SPNEGO with Kerberos. We'll use Java-style configurations here, but an XML configuration can be set up as easily. We can extend the WebSecurityConfigurerAdapter class to configure all we need.

6.1. Maven Dependencies

The first thing we have to set up are the dependencies:

 org.springframework.security.kerberos spring-security-kerberos-web ${kerberos.extension.version}   org.springframework.security.kerberos spring-security-kerberos-client ${kerberos.extension.version} 

These dependencies are available for download from Maven Central.

6.2. SPNEGO Configurations

Firstly, SPNEGO is integrated into Spring Security as a Filter in HTTPSecurity:

@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest() .authenticated() .and() .addFilterBefore( spnegoAuthenticationProcessingFilter(authenticationManagerBean()), BasicAuthenticationFilter.class); }

This only shows the part required to configure SPNEGO Filter and is not a complete HTTPSecurity configuration, which should be configured as per application security requirements.

Next, we need to provide the SPNEGO Filter as Bean:

@Bean public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter( AuthenticationManager authenticationManager) { SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter(); filter.setAuthenticationManager(authenticationManager); return filter; }

6.3. Kerberos Configurations

In addition, We can configure Kerberos by adding AuthenticationProvider to AuthenticationManagerBuilder in Spring Security:

@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .authenticationProvider(kerberosAuthenticationProvider()) .authenticationProvider(kerberosServiceAuthenticationProvider()); }

The first thing we have to provide is a KerberosAuthenticationProvider as a Bean. This is an implementation of AuthenticationProvider, and this is where we set SunJaasKerberosClient as a KerberosClient:

@Bean public KerberosAuthenticationProvider kerberosAuthenticationProvider() { KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider(); SunJaasKerberosClient client = new SunJaasKerberosClient(); provider.setKerberosClient(client); provider.setUserDetailsService(userDetailsService()); return provider; }

Next, we also have to provide a KerberosServiceAuthenticationProvider as a Bean. This is the class that validates Kerberos Service Tickets or SPNEGO Tokens:

@Bean public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() { KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider(); provider.setTicketValidator(sunJaasKerberosTicketValidator()); provider.setUserDetailsService(userDetailsService()); return provider; }

Lastly, we need to provide a SunJaasKerberosTicketValidator as a Bean. This is an implementation of KerberosTicketValidator and uses SUN JAAS Login Module:

@Bean public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() { SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator(); ticketValidator.setServicePrincipal("HTTP/[email protected]"); ticketValidator.setKeyTabLocation(new FileSystemResource("baeldung.keytab")); return ticketValidator; }

6.4. User Details

We've seen references to a UserDetailsService in our AuthenticationProvider earlier, so why do we need it? Well, as we've come to know Kerberos, it is purely an authentication mechanism that is ticket-based.

So, while it's able to identify the user, it doesn't provide other details related to the user, like their authorizations. We need a valid UserDetailsService provided to our AuthenticationProvider to fill this gap.

6.5. Running the Application

This is pretty much what we need to set up a web application with Spring Security enabled for SPNEGO with Kerberos. When we boot up the web application and access any page therein, the web browser should prompt for username and password, prepare a SPNEGO token with Service Ticket, and send it to the application.

The application should be able to process it using the credentials in the keytab file and respond with successful authentication.

However, as we saw earlier, setting up a working Kerberos environment is complicated and quite brittle. If things don't work as expected, it's worthwhile to check all the steps again. A simple mistake like mismatch in the domain name can lead to failure with error messages that aren't particularly helpful.

7. Practical Use of SPNEGO and Kerberos

Now that we've seen how Kerberos authentication works and how we can use SPNEGO with Kerberos in web applications, we may question the need for it. While this makes complete sense to use it as an SSO mechanism within an enterprise network, why should we use this in web applications?

Well, for one, even after so many years, Kerberos is still very actively used within enterprise applications, especially Windows-based applications. If an organization has several internal and external web applications, it does make sense to extend the same SSO infrastructure to cover them all. This makes it much easier for administrators and users of an organization to have a seamless experience through disparate applications.

8. Conclusion

За да обобщим, в този урок разбрахме основите на протокола за удостоверяване на Kerberos. Също така обсъдихме SPNEGO като част от GSS-API и как можем да го използваме, за да улесним Kerberos-базирано удостоверяване в уеб приложение чрез HTTP. Освен това се опитахме да създадем малко уеб приложение, използващо вградената поддръжка на Spring Security за SPNEGO с Kerberos.

Този урок просто предоставя бърз поглед върху мощен и тестван от времето механизъм за удостоверяване. Налице е доста богата информация, за да научим повече и евентуално да оценим още повече!

Както винаги, кодът може да бъде намерен в GitHub.