What is the use of the pre-auth user in SPNEGO SSO configuration? - single-sign-on

I'm using SPNEGO in order to implement SSO solution. During the configuration, I was required to use domain user credentials in 2 steps:
In the web.xml of my application:
<init-param>
<param-name>spnego.preauth.username</param-name>
<param-value>myuser</param-value>
</init-param>
<init-param>
<param-name>spnego.preauth.password</param-name>
<param-value>mypassword</param-value>
</init-param>
In the setspn command: setspn -A <mySPN> myuser
When I used this configuration, the username of the user "myuser" was retrieved by the Java application using getRemoteUser(). So the SSO worked fine. But when I tried to open a session as other users (on the same windows server) it worked also, so I am a little bit confused. This led me to these questions:
Why did the SSO work for all the other users of the domain? Do I have to use the same user in both web.xml and setspn command? And which user to choose? What's the exact use of the SPN in the Kerberos scenario? Do I have to execute the command setspn in every windows computer or there is a way to do it just once?

This account is part of what defines the server's identity within Kerberos.
Kerberos is a symmetric-key protocol. Each user has a symmetric key that's shared between the user and the KDC, and similarly each service (acceptor) has a symmetric key that's shared between the service and the KDC.
When a user requests tickets for a specific "service principal", the KDC will return them encrypted using that service's key. So in order for a service to decrypt those Kerberos tickets, it also needs some way to know the key associated with its own service principal.
Often, the service key is generated randomly and provided through a "keytab" file. However, in Active Directory systems, most service accounts are regular user accounts which have a password – so their key can be derived from the service's password instead.
It seems that your SPNEGO module supports both methods (see lines 150-160) – it can be given a keytab or a password.
In any case, the setting has absolutely nothing to do with the clients that will be connecting to your service. It only establishes the server's own identity.
What's the exact use of the SPN in the Kerberos scenario?
It's similar to the domain name field in HTTPS certificates. For example, when a browser performs Kerberos authentication to https://example.com, it will always request a Kerberos ticket for the SPN HTTP/example.com from the KDC.
If you're familiar with OAuth2 or SAML or JWTs, I believe the Kerberos SPN would be the rough equivalent of the "audience" field in SAML assertions, or the "aud" field in JWTs.
(Note that the browser only knows your service by its SPN, and doesn't care about the actual service accounts that are used behind the scenes – e.g. Active Directory happens to map SPNs to real "user" accounts in this case, but other Kerberos implementations do it differently)
Do I have to use the same user in both web.xml and setspn command?
Yes, it needs to be the same user, because the service must be able to decrypt tickets that were issued for its SPN, so it needs to know the same symmetric key.
And which user to choose?
Create a new, dedicated account just for that service. Do not use a real "person" account.
Use a long, highly random password, and mark it as non-expiring. Additionally, make sure to enable both "Account supports Kerberos AES xxx-bit" features in the account's options (assuming your Java SPNEGO thing supports AES, which it really ought to).
Do I have to execute the command setspn in every windows computer or there is a way to do it just once?
No, it doesn't matter where you execute it, because it only edits the actual account on the domain controllers – it leaves no trace on the local machine. (Specifically, it sets the servicePrincipalName LDAP attribute for the provided account.)
Clients only recognize your service by its SPN, and they have no need to know about the account mapping that's done by the KDC behind the scenes.

Related

OpenID Connect: transparent authentication for legacy clients using Resource Owner Password Credentials

We're currently rewriting various services to use OpenID Connect (via Keycloak).
This works great for any modern browser-based clients, but in our case we also need to support legacy IoT devices, which:
cannot receive a firmware update (and thus are stuck in their current modes of authentication/communication)
are not aware of Keycloak and are not configured to participate in OpenID Connect. (and are also only aware of the application's URL and not the Keycloak URL)
authenticate directly with the application using either Basic Authentication or SSL Client Authentication with a certificate.
From the documentation we gathered that mapping each device to a Keycloak user and using the
Resource Owner Password Credentials would be the way to go in such cases.
We were thinking that it'd be nice to add centralized support for such devices by exposing a reverse proxy that sits in front of all services and performs the following steps:
Receive the IoT device requests (and optionally terminate SSL)
Extract the credentials from the request (either basic auth / client certificate)
Perform the Resource Owner Password Credentials Flow against Keycloak to exchange the credentials for an access token (where the IoT device acts as the OAuth Resource Owner and the reverse proxy acts as the OAuth Client
If successful, enrich the original request with the retrieved access token and forward it to the proxied service
In that way the entire OpenID Connect authentication is transparent for any legacy devices.
This design could be further improved/optimized by caching the access tokens for the duration they are valid for (using the credentials as the cache key) and refreshing them when they expire.
Now, this idea seems like such a no-brainer, that we were surprised that we couldn't find any existing gateways, reverse proxies or plugins that do this.
So I guess we're in need of a sanity check on:
Is this something that can work as described or are there any obvious flaws with the idea?
Why isn't anyone doing this already? (assuming that supporting legacy devices is a major pain point when switching to OpenID Connect)
UPDATE 1: (responding to question) The described legacy IoT devices are (physically) Arduino microcontrollers with baked-in unique credentials. In the context of Keycloak, each such Arduino microcontroller is mapped as a Keycloak user. We're open for suggestions if this is not the most adequate mapping for this use-case.
UPDATE 2: (responding to question) Agreed that the Client Credentials Flow would be semantically more correct for such a device-to-device authentication and any future devices we produce will use it. However we can't use it for the existing legacy devices for two reasons: 1) the devices only know the server's URL and can't authenticate directly against Keycloak and 2) we also want to support SSL Client Authentication using a X.509 certificate and from our understanding Keycloak only supports X.509 client certificate user authentication for users, and not for clients.
Is this something that can work as described or are there any obvious flaws with the idea?
It works fine, so long as your OP supports the Resource Owner Password Credentials flow, which is deprecated and removed from modern OAuth2.
Why isn't anyone doing this already? (assuming that supporting legacy devices is a major pain point when switching to OpenID Connect)
Lots of reverse proxies do this, just not with resource owner credentials. The ROPC flow was never a good idea, exists for legacy reasons, and has been removed from OAuth 2.1.
I suspect that most people move away from storing and transmitting resource owner credentials as they modernize their architecture.

SSO using Kerberos on Windows and Linux

We have a client/server based application that is developed internally. Clients and server communicate over a TCP/IP connection with an application-specific protocol. The clients run on Windows and the server runs on Linux. All machines are in the same Active Directory/Kerberos domain/realm.
Currently, the user enters a username and password when they start the application. The server checks the username and password (authentication). Based on the username, the server also determines access to resources (authorization).
We want to add Single Sign-On (SSO) capabilities to the application. That is, we do not want the user to enter a username and password but we want to automatically logon as the current Windows user.
Of course, determining the current Windows user has to be done securely.
I have come up with the following setup:
I use SSPI (Negotiate) on Windows and GSSAPI on Linux.
When the client connects to the server, it uses AcquireCredentialsHandle (Negotiate) to get the credentials of the current Windows user.
The client uses InitializeSecurityContext (Negotiate) to generate a token based on these credentials.
The client sends the token to the server.
The server uses gss_acquire_cred() to get the credentials of the service. These are stored in a .keytab file.
The server receives the token from the client.
The server uses gss_accept_sec_context() to process the token. This call also returns the "source name", that is the current Windows user of the client.
The server uses the "source name" as the username: the server performs no additional authentication. The server still performs authorization.
This works but I do have some questions:
Is this secure? It should not be possible for the client to specify any other username than the Windows user of the client process. If a user has the credentials to create a process as another user (either legally or illegally) than this is allowed.
Should I perform additional checks to verify the username?
Are there alternative ways to achieve SSO in this setup? What are their pros and cons?
What you've described here is the correct way to authenticate the user. You should not have to worry about the user specifying a different name; that's what Kerberos takes care of for you.
If the client is able to obtain a service ticket, then they must have been able to authenticate against the KDC (Active Directory). The KDC creates a service ticket that includes the user's name, and encrypts it with the service's secret key.
The client would not be able to create a ticket for the server with a fake name, because it doesn't have the necessary key to encrypt the ticket.
Of course, this all assumes that you've set everything up correctly; the client should not have access to the service's keytab file for example, and the service should not have any principals in its key tab except its own.
There's a pretty detailed explanation of how it works here.

Kerberos - SPN and keytabs

I have a project that have embedded jetty with SPNEGO enabled. I would like to be able to run this project locally for development purposes (WITH SPNEGO enabled!)
My question is, is the SPN and keytab associated with a particular server at all or can I use the same set on multiple instances of my service?
Kerberos requires that both the client and server somehow figure the service principal to use without any prior contact. If you have control of both the client and server, you can use any principal you want provided you configure both sides to
use the same principal.
In the SPNEGO case, the client does the "standard" thing and builds a principal based on the hostname of the server. (i.e. I want to talk to www.foo.com, I'll try
requesting an HTTP/www.foo.com service ticket and see if the server accepts it. )
I don't know of any way to get the SPNEGO code in the browser to use a fixed service principal. So in this case you'll need a separate keytab for each server.

How does SPN with Kerberos works

As I understand it,
SPN is an authenticating tool for windows services.
Kerberos is a
user authentication service
SPNEGO-GSSAPI is the third party API to
be able to use those services.
SSPI : is the Neutral layer to send
request from SPNEGO to SPN service.
Am I completely lost?
Trying to figure out how it works but information, is either too precise or not enough.
Ok a more verbose answer:-
SPN - Service Principal Name. It is an identifier associated with each account in a KDC implementation(AD, OpenLDAP etc). Basically if your account acts as a service to which a client authenticates, the client has to specify "who" it wants to communicate to. This "who" identifier is the SPN. This is the strict definition. Many people often call the client name (UPN - User Principal Name) of a service as SPN. This happens when the service itself may act as a client( google the delegation scenario ). This is not strictly correct but widely assumed true.
Kerberos is a protocol for authentication. It is a name for a framework. It involves a third party server(called KDC or Key Distribution Centre) and involves a series of steps of acquiring tickets(tokens of authentication). It is really complicated so http://en.wikipedia.org/wiki/Kerberos_(protocol)
To some extent you got this right. GSSAPI is an API but SPNEGO is not. GSSAPI is technically agnostic to the auth mechanism you use, but most folks use it for kerberos authentication. SPNEGO is a pseudo mechanism, in the sense it declares an RFC for authentication based communication in HTTP domain. Strictly speaking SPNEGO is a specification but most folks also consider it as an implementation. For instance, Sun and IBM JDK provides "mechanism providers" for SPNEGO token generation but GSSAPI is used to actually call it. This is done in many projects(Tomcat as a Server is and example that come to the top of my head and one of the folks who answered this question developed it).
SSPI is an analogue to GSSAPI in windows. Its a different API which ends up doing something very similar to GSSAPI.
Not quite.
SPN simply means 'Server Principal Name' and is the AD or Kerberos slang for the service you try to authenticate against.
Kerberos is a user authentication service, more or less yes. It also provides security for network messages and calls between services.
SPNEGO-GSSAPI* is a kind of strange beast. GSSAPI (Generic Security Service Application Program Interface) is an API to (in principle) different authentication services, it provides negotiation of the mechanisms used. Often the only mechanism available will be Kerberos though. It is the usual API to attach 3rd party programs to Kerberos when you are on Unix (defined in various RFCs, for example RFC 2743 )
On the windows platform SSPI is the generic layer, so it compares to GSSAPI.
SPNEGO is kind of a strange hybrid. It is a mechanism to be used in SSPI, HTTP Auth or GSSAPI which negotiates another auth protocol (for example Kerberos or NTLM if you are on Windows), so it basically does the same thing GSSAPI does again in a different way.
Typical uses of SPNEGO are HTTP authentication to a windows domain, for example IIS uses it if you use 'Integrated windows authentication'. It is also used when you select the 'Negotiate' options for SSPI. See for example RFC 4559
Almost all of your understandings are wrong.
Here it goes:
SPN: A specific service-class is bound to a specific account, e.g. HTTP to www.stackoverflow.com => HTTP/www.stackoverflow.com#STACKOVERFLOW.COM
Yes
3./4. GSS-API (Unix)/SSPI (Windows): Mechanism neutral API to interact with. E.g, Kerberos 5, NTLM, SPNEGO, etc.
SPNEGO: It is one of many mechnisms supported by GSS-API/SSPI. It is actually a pseudo-mech.

Kerberos/negotiate S4U2proxy authenticate on behalf of user

I would like to do authentication at proxy on behalf of user via Kerberos/Negotiate protocol.
user will authenticate with form login with server, server knows the who the user is, and server has to authenticate to backend server on behalf of user using kerberos.
Please help me with sample code or point me to some good references.
thank you in advance
-csr
Michael: the OP is asking about what MS calls "constrained delegation," the S4U Kerberos extension they invented, rather than the standard delegation (TGT forwarding) to which you're referring.
CSR: first off: is the user providing their Kerberos password in your "form login?" If so, you don't need to use S4U; you can just kinit with the password and get credentials directly.
If not, then this is indeed one use case for which S4U is intended. You didn't say, but I'll assume you're in a Windows environment, although S4U has been added to MIT Kerberos as well.
Rather than have the client forward a TGT, S4U allows the domain administrator to authorize a service principal to independently impersonate any user to a limited set of other services. To enable a service for constrained delegation:
MMC "Users and Computers" snap-in
select the properties for the service account
"Delegation" tab
"trust... for delegation to specified services"
In your case, you'll also need to set "use any authentication protocol;" this enables "protocol transition." If your service were authenticating the user with Kerberos, you could have the DC require the service to present a recent ticket from the client, proving it has some business doing this. Since you're using different authentication method, though, you have to forgo that check; that's what protocol transition does.
I'd start here for understanding S4U: http://msdn.microsoft.com/en-us/library/cc246071(PROT.13).aspx.
I have written a patch for Apache mod_auth_kerb implementing constrained delegation for Unix web services, so it does in fact work. :)
Have the client to send a forwardable (OK-AS-DELEGATE) ticket to you. You can extract the TGT from that and impersonate to perform your task. This works in my case when I receive a service ticket from IE or FF and bind against the AD for the user.