How to provide public access to web api? - iis

I deployed the code in iis (under default web site), what i need to do to access this api from an external consumer (provide public access).
Can anybody explain how the following works, and what is the username and password here(which username and password)?
*****IIS listens on all the specified ports for requests employing a URL of the general format:
protocol://[username:password#]domain[:port]/path/file[?parameters]*****

Some clients provide support for providing the username and password for basic authentication as part of the URL. You can refer to RFC 1738 for more information.
From Section 3.1
While the syntax for the rest of the URL may vary depending on the
particular scheme selected, URL schemes that involve the direct use
of an IP-based protocol to a specified host on the Internet use a
common syntax for the scheme-specific data:
//<user>:<password>#<host>:<port>/<url-path>
Some or all of the parts ":#", ":",
":", and "/" may be excluded. The scheme specific
data start with a double slash "//" to indicate that it complies with
the common Internet scheme syntax. The different components obey the
following rules:
user
An optional user name. Some schemes (e.g., ftp) allow the
specification of a user name.
password
An optional password. If present, it follows the user
name separated from it by a colon.
Postman Echo has some public endpoints that you can use for testing different auth mechanisms. You can use their Basic Auth endpoint to do some testing. Another way to use Basic Auth is to set the Authorization header with the credentials encoded as a Base64 string; if the server can decode the string and validate the credentials, it'll authenticate you and allow the request.
An example of an Authorization header using Basic Auth:
Authorization: Basic cG9zdG1hbjpwYXNzd29yZA==
You also want to ensure that your requests are being sent over SSL.
Hope this helps!

Related

Pros/cons security architecture for SPA / Backend

I'm not an advanced security developer (what else is new)
Context : I have a monolith using authn/authz mecanism based on a custom JWT stored inside the angular app and refresh frequently. A bit housemade. I'm breaking my monolith one module at a time. And now is about how to handle the security.
I have :
multiple angular apps
multiple Swing apps
multiple back (a big monolith and multiple classic webapplications)
I would like to switch to openid connect. I can :
put a reverse proxy (nginx, kong, ...) with an oidc plugin creating a virtual protected domain for the backends.
From the SPA viewpoint :
Use of code authorization flow with PKCE
When the SPA sends an http request to the RP , the RP check the JWT, validate it, send a 401 if invalidate/missing header.
the SPA redirects the user to the Idp / login page.
Now I'm a bit lost and need to check the Internet :) : I don't know what is the redirect url (the RP or the SPA ? I was assuming only the RP proxy is registered in the Idp)
When the RP forward the original request , the header x-userinfo is set and the backends only read this one.
For back to back communication, we propagaded the x-userinfo header received.
no reverse proxy and each backend checks Authorization Bearer header and redirect to an Authorization server when invalidate or missing. Each back manages the security concerns (validation, redirection, registration).
As you can see I have a lot of misunderstandings. My questions are :
is reverse proxy a good idea ?
is it easier to put a RP with legacy systems (only one header to check ?)
we're putting authz logic inside a RP .... hmmm...
I don't have all the steps inside my head (how the redirections are handled)
when a Swing app (already logged in) wants to redirect the user to a new feature --> open a browser window to an angular app, is there a way to handle the security or do I need to let the angular app handle this (and perhaps force the user to relog into the Idp to obtain a JWT into its cookie/localStorage ?).
Thank you
1a. The redirect URI is the SPA's web origin and should be what you see in the browser. Redirects always occur in the browser (the front channel).
2a. For newer components aim for a zero trust architecture. In OAuth this just means pass a JWT access token to each API. Aim to avoid passing sensitive data used for authorization in headers.
1b. Reverse proxy is an excellent practice for your APIs - as discussed in this IAM Primer. It may be less useful for static web content though, since you may want to deploy that via a content delivery network.
2b. Each app should get its own tokens and redirect the user once - usually a single sign on. In 2021 it is recommended to use secure cookies in SPAs and these cab contain tokens.
Some generic authorization logic can be done in the RP - that is pretty coomon. The real domain specific authorization should be done in APIs though, using scopes and claims.
SUMMARY
Aim to follow best practices for newer components. The Curity links above explain these in a way that cab work for any provider. Hopefully it gives you some useful pointers.

Understanding Entity ID when URI is URL should I use HTTP or HTTPS

When setting up an SSO solution, in my case using Okta, there are the following elements to define:
IdP Server Issuer/Entity ID - http://www.okta.com/dskjeoirueiuaksjdkfj
SP Issuer/Entity ID - http://www.myapp.com/IDP
Given that these are URIs I have read it doesn't matter if the protocol is defined as either http:// or https://. I am trying to understand if this is true and if so why/why not.
I also read, while it technically does not matter if http:// or https:// is used, that https:// is more flexible. However no explanation was given as to why.
An entityID is just the "handle" for your Identity Provider (IdP). It should be constant across all the Service Providers you interact with.
The recommendation is that you own the domain with a view to hosting your metadata at a resolvable uri.
The UK federation explains that https is recommended because:
https scheme entity IDs can be constructed to be compatible with
alternative metadata publishing schemes, such as that described in
section 4.1 of the SAML 2.0 metadata specification
For example, another federation might not publish your metadata if your entityID uri is resolvable to an http url. They may prefer https.
SAML 2.0 metadata specification PDF

When registering an app on Azure Active Direct, what "redirect URI" or "Sign-on URL" should I use?

Might seem a silly question, but Microsoft's documentation isn't very beginner friendly, I think. It uses as examples "http://localhost:31544" for the sign-on url and "http://MyFirstAADApp" for the redirect URI, but although I understand what a local host is I can't figure out what exactly the numbers on it are and how I define them for my application, and absolutely zero clue of what the redirect URI is supposed to do for a native application and how should I define a URI for my own.
To be more clear on what kind of app I'm trying to add, I merely want to acess the Office 365 management API tools and get some data from it, so I imagine a native app would fulfill my needs for now. Registering the app on Azure AD is required to do so according to Microsoft's documentation.
So expanding on the title, how to define an URI for my native app is what I would mainly like to know. Some further clarification on what exactly is the purpose of this URI as well as to how to use and/or define a localhost URL for an Web app would also be much appreciated.
I know this is ancient, but I don't see a satisfying answer here, and maybe someone will come across this and find it useful. To answer the question asked, unless you're going to work outside of the default MSAL handling of the server responses, and I don't expect you would from your description, I'd just go ahead and use the default:
https://login.microsoftonline.com/common/oauth2/nativeclient
When you go into the Azure AD portal, go to your application and, from the Overview, select the "Set RedirectURL" option, you'll add a platform and select the "Mobile and Desktop Applications" and you'll be provided with the choice of 3 URLs to choose from. My understanding is this is just there for custom handling of authorization tokens and is telling MS where to send those tokens. The MSAL library functions seem to use this link as well, so they're probably handling this in the backend.
I agree with the OP though, the MS docs are severely lacking for newcomers and I wasn't able to find an end-to-end description of what needs to happen to get, in my case, a desktop application to send email through Office365 using 2FA. I would forge ahead as best I could until I hit the next error, then explore that, sort it, then slam into the next one. Rinse and repeat. This was made extra tedious as I had to go through a 3rd party IT group to get the 2FA access codes every time I wanted to test.
Best of luck, hope this helps someone!
how to define an URI for my native app is what I would mainly like to
know.
You should provide a Redirect URI that is unique to your application as it will return to this URI when authentication is complete.
In your application, you will need to add a class level variables that are required for the authentication flow, include ClientId and Redirect URI.
Here is the diagram:
Native application makes a request to the authorization endpoint in Azure AD, this request includes the Application IP ,Redirect URI and application ID URI for the web api.
After user signed in, Azure AD issues an authorization code response back to the client application's redirect URI. After that, the client application stops browser interaction and extracts the authorization code from the response.
Then the client app use this code to sends a request to Azure AD's token endpoint. upon successful validation, Azure AD returns two tokens.
Over HTTPS, the client app uses the returned JWT access token to add the JWT string with a “Bearer” designation in the Authorization header of the request to the web API. The web API then validates the JWT token, and if validation is successful, returns the desired resource.
More information about it, please refer to this article.
For native you can set redirect to be equal to the Application ID URI, which now defaults to look like //app:{ApplicationId}
Redirect uri be starts with SSL URL, so select your project, enable SSL URL and use this auto generated SSL URL (for example : https://localhost:port#) as redirect uri , same to be updated in the azure app registration as additional redirect URIs

Securing a https connection

I have exposed some rest services in spring, using spring mvc, I have secured the webapp using spring security, that uses bcrypt on the server to encode the password and store it in the datbase.
The user will send the password in the url in plain text under https, And i have written a custom basic_auth_filter to check the uername and passowrd - basically authenticate. I also have set up a firewall that only allows one ip to connect.
Im no security expert, is there anything else i need to, should i encode the username/password in the url.. even though it will be coming via https?
regards
ps. this was a requirement to use username on the url?
Passwords, and all other non-ephemeral credentials, should never be sent in the URL, if for no other reason then because the browsers and other HTTP tools and servers will remember this in history, various logs etc, HTTPS or not, making it trivial to steal by anyone with local access, or even by someone just looking over your shoulder. This is why Spring by default rejects authentication via GET requests.
For this reason, you should move the sensitive parameters to the body of the request (thus requiring a POST).
If your login flow is based on username/passwords, I recommend you use UsernamePasswordAuthenticationFilter as it already encapsulates the logic and best practices for this type of flow.
In general your scheme is secure.
Consider pinning the server, that is validating the server certificate, to ensure the connection is to your server.
The password should not be used other than to authenticate using (in your case) bcrypt.
Re question update: "HTTPS encrypts the query string, only the actual server address portion is un-encrypted. But, the full URL including query string will probably be logged by the server so that has security implication. It is best to send confidential information in a POST.

What TargetName to use when calling InitializeSecurityContext (Negotiate)?

The Question
When calling InitializeSecurityContext, what value do i pass to the TargetName parameter?
Revised Background
I'm calling the function InitializeSecurityContext:
InitializeSecurityContextA(
#pAS.hcred, //[in] credentials
phContext, //[in] optional] Context handle structure
pszTargetName, //[in, optional] Target name
0, //[in] context requirements
0, //[in] reserved1, must be zero
SECURITY_NATIVE_DREP, //[in] target data representation
pInput, //[in] optional] SecBufferDescription
0, //[in] reserved2, must be zero
#pAS.hctxt, //[in, out] pointer to context handle structure
#OutBuffDesc, //[in, out] pointer to SecBufferDesc
ContextAttributes, //[out] context attributes
#lifetime); //[out] expiration timestamp
What do i pass to pszTargetName?
I've tried
null: InitializeSecurityContextA(#pAS.hcred, phContext, null, ...);
"": InitializeSecurityContextA(#pAS.hcred, phContext, "", ...);
"spn/HOSTNAME": InitializeSecurityContextA(#pAS.hcred, phContext, "spn/HOSTNAME", ...);
spn/HOSTNAME.DOMAIN.COM: InitializeSecurityContextA(#pAS.hcred, phContext, "spn/HOSTNAME.DOMAIN.COM", ...);
"cargocult/PROGRAMMING": InitializeSecurityContextA(#pAS.hcred, phContext, "cargocult/PROGRAMMING", ...);
"http/TFS.DOMAIN.COM": InitializeSecurityContextA(#pAS.hcred, phContext, "http/TFS.DOMAIN.COM", ...);
"http/HOSTNAME": InitializeSecurityContextA(#pAS.hcred, phContext, "http/HOSTNAME", ...);
"qwertyasdf": InitializeSecurityContextA(#pAS.hcred, phContext, "qwertyasdf", ...);
"AuthSamp": InitializeSecurityContextA(#pAS.hcred, phContext, "AuthSamp", ...);
They all either fail, or downgrade to NTLM.
Note: My machine is domain joined, but the domain is not named domain.com, or even hostname.domain.com, or even qwertyasdf. So i'm not surprised that those attempts fail. But people said try things like http/HOSTNAME, so i put in http/HOSTNAME.
Background
The InitializeSecurityContext (Negotiate) function has an optional TargetName parameter:
pszTargetName [in, optional]
A pointer to a null-terminated string that indicates the service principal name (SPN) or the security context of the destination server.
Applications must supply a valid SPN to help mitigate replay attacks.
What is this supposed to be?
More Background
i am trying to validate a set of user's credentials, e.g.:
Boolean ValidateCredentials(String username, String password, String domain)
{
...
}
Validating a set of user's credentials requires using the SSPI API. The first function to call is InitializeSecurityContext. One of the parameters to InitializeSecurityContext is a "TargetName" string.
i've tried leaving it null, but the Application Verifier triggers a breakpoint, writing out the error:
VERIFIER STOP 00005003: pid 0xF08:
InitializeSecurityContext uses NULL target or malformed target for Kerberos service.
Please see pszTargetName for the value of the target.
00000000 : Not used.
00000000 : Not
At this point it would be helpful to remember that the Negotiate provider will attempt to use Kerberos, but fallback to NTLM. In the case of Negotiate, Kerberos or NTLM, the TargetName parameter is documented to be:
Service principal name (SPN) or the security context of the destination server.
But then what should i pass?
i tried doing what the SSPI Knowledge Base article does, nothing (i.e. pass NULL):
How to validate user credentials on Microsoft operating systems
ss = _InitializeSecurityContext(
&pAS->hcred,
pAS->fInitialized ? &pAS->hctxt : NULL,
NULL, //<-------pszTargetName
0,
0,
SECURITY_NATIVE_DREP,
pAS->fInitialized ? &sbdIn : NULL,
0,
&pAS->hctxt,
&sbdOut,
&fContextAttr,
&tsExpiry);
But nothing (i.e. NULL) doesn't work.
Note: The KB article was massivly rewritten in 2007. In its original 1999 incarnation they passed "AuthSamp" as the target, but that also fails.
Bonus Chatter:
service principal name
(SPN) The name by which a client uniquely identifies an instance of a service. If you install multiple instances of a service on computers throughout a forest, each instance must have its own SPN. A given service instance can have multiple SPNs if there are multiple names that clients might use for authentication
security context
The security attributes or rules that are currently in effect. For example, the current user logged on to the computer or the personal identification number entered by the smart card user. For SSPI, a security context is an opaque data structure that contains security data relevant to a connection, such as a session key or an indication of the duration of the session.
Bonus Chatter 2
From the application verifier documentation:
The Verifier plug detects the following errors:
The NTLM package is directly specified in the call to AcquireCredentialsHandle (or higher level wrapper API).
The target name in the call to InitializeSecurityContext is NULL.
The target name in the call to InitializeSecurityContext is not a properly-formed SPN, UPN or NetBIOS-style domain name.
The latter two cases will force Negotiate to fall back to NTLM either directly (the first case) or indirectly (the domain controller will return a “principal not found” error in the second case causing Negotiate to fall back).
The plug-in also logs warnings when it detects downgrades to NTLM; for example, when an SPN is not found by the Domain Controller. These are only logged as warnings since they are often legitimate cases – for example, when authenticating to a system that is not domain-joined.
In my case the domain i am validating against is null (since i don't know the machine's domain name, or even if there is a domain). But the results are the same if the hard-code my development machine's domain name.
Update 3
Values of pszTargetName that trigger AppVerifier error, but logon succeeds:
null
""
"AuthSamp"
"qwertyasdf"
*the name of the domain i'm validating against (e.g. "avatopia.com")
*the name of the domain the machine is joined to (e.g. "avatopia.com")
*the name of the domain the user account is located in (e.g. "avatopia.com")
Values of pszTargetName that do not trigger an AppVerifier error, but logon fails:
"http/HOSTNAME"
"http/TFS.DOMAIN.COM"
"frob/GROBBER"
"cargocult/PROGRAMMING"
"spn/HOSTNAME"
"spn/HOSTNAME.DOMAIN.COM"
Values of pszTargetname that do not trigger an AppVerifier error, and logon succeeds:
none
Update 4
What i'm trying to do: figure out if a username/password is valid.
i have a username: e.g. "ian"
i have a password: e.g. "pass1"
Now there's the further wrinkle that the account ian could be a local account or a domain account. And you need to decide if ian is a local or domain account before you can ask. This is because ian can have two accounts:
ian on domain stackoverflow.com
ian on local machine
So i need to specify if i want to:
ask a particular domain (e.g. stackoverflow.com), or
ask the local machine (which i'll represent as ".")
Now we can come up with a cross reference:
Username Password Domain Machine on domain? Validate as
======== ======== ================= ================== ==============
iboyd pass1 . No Local account
iboyd pass1 (empty) No Local account
iboyd pass1 stackoverflow.com No Domain account
iboyd pass1 . Yes Local account
iboyd pass1 (empty) Yes Domain account
iboyd pass1 stackoverflow.com Yes Domain account
Update 5
It might help to explain what i'm trying to do, then maybe how to do it will become easier. Lets say i walk into a random office building downtown, walk into a random cubicle, and type in a random username and password:
i'm going to try to login to the domain TURBOENCABULATOR. i specified i want to try to authenticate against the TURBOENCABULATOR domain by prefixing my username as:
TURBOENCABULATOR\ian
Note: i highly doubt the network has a domain called turboencabulator, since the name itself only comes from Rockwell automation. The attempt to login will almost certainly fail. But how does Windows check them?
How does Windows attempt to validate these credentials? How does Windows validate the credentials:
Username: ian
Password: pass1
Domain: TURBOENCABULATOR
Does Windows use the Security Support Package Interface? Assuming windows uses Negotiate or Kerberos for authentication, what does Windows pass as the pszTarget parameter? Almost certainly the credentials i enter will not be valid. How will Windows determine if they are valid? What API will Windows call to validate the credentails?
Windows is able to validate credentails. I want to also validate credentials.
Perhaps instead of trying to connect to the TURBOENCABULATOR domain, i try to connect to the turboencabulator.com domain by prepending the domain to my username as turboencabulator.com\ian:
Same question applies. How does Windows validate credentials? i want to do what Windows does. Assuming Windows uses kerberos for authorization, what does Windows pass as the pszTargetName parameter in SSPI?
Perhaps instead of trying to connect to the turboencabulator.com domain, i try to connect to the turboencabulator.net domain:
Note that in this example i've appended the domain name to my username, rather than prepending it.
Perhaps instead of trying to connect to the turboencabulator.net domain, i try to validate the user as a local (machine) account by prefixing my username with .\ as:
How does Windows validate the username and password against the local account database? Does it use SSPI with Negotiate package? If so what value does it pass as the pszTargetName?
People are talking about web servers, http, team foundation server. i really don't know where they're getting that from. Or they talk about editing a user in active directory to ensure something is present - i don't see why i need to edit anything: Windows doesn't edit anything.
What TargetName do i used when calling InitializeSecurityContext in order to validate a set of credentials?
Bonus Chatter
Here's a chapter from the Application Verifier documentation about why they have a test if someone is mistakenly using NTLM:
Why the NTLM Plug-in is Needed
NTLM is an outdated authentication protocol with flaws that
potentially compromise the security of applications and the operating
system. The most important shortcoming is the lack of server
authentication, which could allow an attacker to trick users into
connecting to a spoofed server. As a corollary of missing server
authentication, applications using NTLM can also be vulnerable to a
type of attack known as a “reflection” attack. This latter allows an
attacker to hijack a user’s authentication conversation to a
legitimate server and use it to authenticate the attacker to the
user’s computer. NTLM’s vulnerabilities and ways of exploiting them
are the target of increasing research activity in the security
community.
Although Kerberos has been available for many years many applications
are still written to use NTLM only. This needlessly reduces the
security of applications. Kerberos cannot however replace NTLM in all
scenarios – principally those where a client needs to authenticate to
systems that are not joined to a domain (a home network perhaps being
the most common of these). The Negotiate security package allows a
backwards-compatible compromise that uses Kerberos whenever possible
and only reverts to NTLM when there is no other option. Switching code
to use Negotiate instead of NTLM will significantly increase the
security for our customers while introducing few or no application
compatibilities. Negotiate by itself is not a silver bullet – there
are cases where an attacker can force downgrade to NTLM but these are
significantly more difficult to exploit. However, one immediate
improvement is that applications written to use Negotiate correctly
are automatically immune to NTLM reflection attacks.
By way of a final word of caution against use of NTLM: in future
versions of Windows it will be possible to disable the use of NTLM at
the operating system. If applications have a hard dependency on NTLM
they will simply fail to authenticate when NTLM is disabled.
How the Plug-in Works
The Verifier plug detects the following errors:
The NTLM package is directly specified in the call to AcquireCredentialsHandle (or higher level wrapper API).
The target name in the call to InitializeSecurityContext is NULL.
The target name in the call to InitializeSecurityContext is not a properly-formed SPN, UPN or NetBIOS-style domain name.
The latter two cases will force Negotiate to fall back to NTLM either directly (the first case) or indirectly (the domain controller will return a “principal not found” error in the second case causing Negotiate to fall back).
The plug-in also logs warnings when it detects downgrades to NTLM; for example, when an SPN is not found by the Domain Controller. These are only logged as warnings since they are often legitimate cases – for example, when authenticating to a system that is not domain-joined.
NTLM Stops
5000 – Application Has Explicitly Selected NTLM Package
Severity – Error
The application or subsystem explicitly selects NTLM instead of Negotiate in the call to AcquireCredentialsHandle. Even though it may be possible for the client and server to authenticate using Kerberos this is prevented by the explicit selection of NTLM.
How to Fix this Error
The fix for this error is to select the Negotiate package in place of NTLM. How this is done will depend on the particular Network subsystem being used by the client or server. Some examples are given below. You should consult the documentation on the particular library or API set that you are using.
APIs(parameter) Used by Application Incorrect Value Correct Value
===================================== =============== ========================
AcquireCredentialsHandle (pszPackage) “NTLM” NEGOSSP_NAME “Negotiate”
See also
InitializeSecurityContext parameter pszTargetName
Ian, I think we still don't understand what you are trying to do exactly. In order to help you providing us more information on what you are trying to do, here is a little bit background about SSPI. You may already know this but just to make sure we are on the same page.
SSPI is generally used for authenticating a user over the network. Client calls the AcquireCredentialsHandle to obtain a credentials handle and then create a security context by calling InitializeSecurityContext. Pass the security buffer to server. Note that SSPI doesn't dictate how you pass the security buffer. You can use http, tcp, named pipe whatever you like. Once the server receive the security buffer. Similarly, it calls the AcquireCredentialsHandle first. Then it passes the received security buffer into AcceptSecurityContext and generate new security buffer. In some cases, the newly generated security buffer needs to send back to the client and client passes that into InitializeSecurityContext and generates another new security context again. This SSPI handshaking process continues until InitializeSecurityContext and AcceptSecurityContext both returns SEC_E_OK
Although SSPI was designed for authentication over the network, many applications are actually doing loopback SSPI handshaking, which means both client and server are on the same box. This is really just a special case of the network authentication. The end result of a loopback SSPI handshaking is a authenticated SSPI security context. With this authenticated SSPI, application can do QueryContextAttributes and ImpersonateSecurityContext. Since you seem to have no idea what targetName means, I am guessing you are trying to do the loop back handshaking. I might be wrong though but you need to tell us what you are trying to do.
To understand why targetName is needed in Kerberos but not in NTLM, you need to understand some more underlying implementation.
There are two different ways to acquire a credentials handle. Normally, people specify to use the current security context. (i.e. the account that you used to log onto your machine). You can also provide another set of username/password. Different security package has different meanings on the term credentials. NTLM means that it's going to save a hash of your password. Kerberos means that it's going to save a Ticket Granting Ticket (TGT). To the SSPI programmer, you don't need to worry about this.
Now, when the client passes in the acquired credentials handle into InitializeSecurityContext, similarly, different security package is going to do different things. NTLM is going to generate a NEGOTIATE packet on the first InitializeSecurityContext call. No other machines are involved in the process of generating the NEGOTITATE packet. Kerberos package is very different. It's going to talk to KDC to request a service ticket for the requested service. The service is identified by Service Principal Name (SPN) in Kerberos. I cannot cover all the details here. The net net is that service request for NTLM is untargeted while the service request for Kerberos is targeted. You can use the same NTLM NEGOTIATE packet for different services using NTLM authentication method. However, you need to use different Kerberos service tickets for different services using Kerberos authentication method. That's why when calling InitializeSecurityContext for Kerberos / Negotiate, you need to provide the targetName.
When KDC receives the request of a service ticket, it does a search on its LDAP database and find out which account is associated with the specified servicePrincipalName. The account can be AD user account or AD computer account. The KDC will use the target service account's master key (generated by the account password) to encrypt a session key. This encrypted session key will be passed from the client to the server later on.
Now, remember I said the server also needs to do AcquireCredentialsHandle and I said there are two major approaches to get the credentials handle? I guess your are using the first approach to acquire the credentials handles. That means it is going to use the current security context. In a normal network authentication case, this can be illustrated by the following example. If your sever is a HTTP server, it's going to be the service account of your IIS server. IIS server is going to use its service account master key to decrypt the encrypted session key. Once the session key is obtained, client and server continues the communication using the session key to do the encryption and decryption.
If it is a loop back SSPI scenario, it's trickier. If you are running domain\jane and doing loop back on yourself. You need to specify a SPN for domain\jane. What's the SPN for domain\jane. If you check the AD user object, there is none by default. You need to manually fix it.
There is one thing that used to work for me but it's undocumented. You can specify the user's UPN (i.e. jane#domain.com) as the SPN. This works for me. You can try it.
If that doesn't work, another way to fix it is to use the second approach to do the server part AcquireCredentialsHandle. Instead of using domain\jane credentials handle, you specify another service account credentials. You can make sure that service account has a correct SPN set. Then, you can use that service account's SPN in your InitializeSecurityContext. Of course, that also means you need to hard code your service account's password in the code. You need to be careful and make sure you completely lock down this service account so that even though the password is stolen, your AD environment is not at big risk.
Short Answer
The TargetName is the username that the "server" code will be running as.
I'm logged in as ian#stackoverflow.com
I want to prove my identity to steve#stackoverflow.com
Set TargetName to steve#stackoverflow.com
Background
The Negotiate authentication package will attempt to use Kerberos. If it cannot, it will attempt to fallback to NTLM.
You don't want to use NTLM; it is old, deprecated, weak, broken, and should not be used.
You want to use Kerberos.
In order to use Kerberos you must supply a TargetName
Without a TargetName, Kerberos is fundamentally unable the function
The question becomes, given all the parties involved:
me (Ian)
authenticating with Steve
what TargetName do i specify?
This is where it's important to know what TargetName means to Kerberos:
i want to prove my identity to steve#stackoverflow.local
the domain controller hands me an encrypted blob that proves my identity
the blob is encrytped so steve#stackoverflow.local is the only one able to decrypt it
the domain controller knows to encrypt it for steve#stackoverflow.local because i specified steve#stackoverflow.local in the TargetName
Steve is the target
That's how Steve knows the blob is valid, it was encrypted so only he can decrypt it.
I have to tell Kerberos who i will be giving the encrypted blob to, so the domain controller knows who to encrypt it for.
So in the above list of possible names, three values work:
InitializeSecurityContext(credHandle, context, "steve#stackoverflow.local", ...);
InitializeSecurityContext(credHandle, context, "stackoverflow.local\steve", ...);
InitializeSecurityContext(credHandle, context, "steve", ...); //if we're in the same forest
So you can see why my earlier attempts to call InitializeSecurityContext all failed:
InitializeSecurityContextA(credHandle, context, null, ...);
InitializeSecurityContextA(credHandle, context, "", ...);
InitializeSecurityContextA(credHandle, context, "spn/HOSTNAME", ...);
InitializeSecurityContextA(credHandle, context, "spn/HOSTNAME.DOMAIN.COM", ...);
InitializeSecurityContextA(credHandle, context, "cargocult/PROGRAMMING", ...);
InitializeSecurityContextA(credHandle, context, "http/TFS.DOMAIN.COM", ...);
InitializeSecurityContextA(credHandle, context, "http/HOSTNAME", ...);
InitializeSecurityContextA(credHandle, context, "qwertyasdf", ...);
InitializeSecurityContextA(credHandle, context, "AuthSamp", ...);
Because i wasn't specifying Steve as the TargetName; i was specifying something non-sensical:
spn/HOSTNAME
In fairness, people did keep telling me to pass "spn/HOSTNAME".
Extra confusion because flexibility (welcome to SPN)
SPNs Short version
when using Kerberos you must specify a username as your TargetName
an SPN is an "alias" for a username
therefore you can specify an SPN as your TargetName
SPNs Long Version
In the case above i had to know that the "server" code will be running as steve#stackoverflow.local.
That's a pain. I mean it's fine when i know it's steve. But if i'm talking to a remote machine, i have to find out the user account that the code is running as?
i have to figure out that IIS is running as iisagent#stackoverflow.local?
i have to figure out that SQL Server is running as sqldaemon#stackoverflow.local?
and what if the service is running as Local Service; that isn't a domain user at all?
Fortunately(?), Kerberos created aliases (called Service Principle Names - or SPNs):
if i need to authenticate to the web server http://bugtracker.stackoverflow.local
and IIS service is running under the domain account iisagent#stackoverflow.local
rather than have to specify the targetname of iisagent#stackoverflow.local
i can specify HTTP/bugtracker.stackoverflow.local
that's because IIS registered an alias with the domain controller
HTTP/bugtracker.stackoverflow.local → iisagent#stackoverflow.local
All this requires that you know the SPN if you wish to use it as a TargetName. Various standard Microsoft products register SPNs when they install:
IIS: HTTP/[servername]
SQL Server: MSSQLSvc/[servername]:1433
SMTP: SMTPSVC/[servername]
File sharing: HOST/[servername]
These are all undocumented, and make your life hell when one isn't configured correctly.
But by no means do you have to supply a SPN. An SPN is simply an alias designed to make your life easier more difficult.
It's roughly equivalent to attempting to specify "stackoverflow.com", rather than simply using "35.186.238.101".
Bonus Chatter - How does SSPI work?
SSPI was designed as a generic wrapper around different security algorithms. The way to use the API is pretty simple:
Client: calls InitializeSecurityContext and is given a blob
client sends that blob to the server
Server: calls AcceptSecurityContext(blob), and is given a blob back
server sends that blob back to the client
Client: calls InitializeSecurityContext(blob), and is given back a blob
client sends that blob back to the server
Server: calls AcceptSecurityContext(blob), and is given a blob back
...keep repeating until told to stop...
Both sides keep going back and forth until the function stops returning a blob that needs to be sent to the other side:
And so the with SSPI you do this ping-ponging back and forth until you're told to stop. And so they were able to shoe-horn every authentication scheme into that ping-pong-until-told-to-stop high level abstraction.
How do I transmit the blobs?
You transmit the blobs over whatever communication channel you're using.
If you're talking to a remote server over TCP/IP, then you'd probably use that:
// Open connection to server
sockConnect(162.210.196.166, 1433);
blob = null;
Boolean bContinue = InitializeSecurityContext(ref blob);
while (bContinue)
{
sockWrite(blob); //send the blob to the server
blob = sockRead(); //wait for the server to return a blob
bContinue = InitializeSecurityContext(ref blob);
}
If you're doing it over http:
blob = null;
Boolean bContinue = InitializeSecurityContext(ref blob);
while (bContinue)
{
http = new HttpRequest("http://4chan.org/default.aspx");
http.AddHeader("X-SSPI-Blob", blob.ToBase64());
http.Send();
blob = http.ReasponseHeader["X-SSPI-Blob"];
if (blob.IsEmpty())
break;
bContinue = InitializeSecurityContext(ref blob);
}
The SSPI API doesn't care you to get the blob transmitted back and forth - just that you have to transmit it back and forth.
using connecting to SQL Server, SQL client driver does the transmitting over the database connection
using http, the browser sends the blobs in request and response header
You can even use a carrier pidgeon, Skype, or E-mail if you like.
I am a couple years late to this party... Yesterday, I came across your question while researching my own SSPI issue. This morning as I continued my research, I came across an article by By Keith Brown, from the April 2001 MSDN Magazine, that seems to offer a solution to your question:
Security Briefs - The Security Support Provider Interface Revisited (archive)
by Keith Brown
From the April 2001 issue of MSDN Magazine.
The "Figures" referenced in the article (including the example code) is located here (archive)
The article contains example code which reveals the targetName (for the purpose of password validation) should be a string in the form "Machine\User" or "Domain\User".
I realize you likely found a solution to this issue a long time ago. Furthermore, I cannot certify that the author's code functions correctly on modern Windows platforms (I suspect it would, but I have not validated the behavior)
Hopefully the MSDN article will also be a useful resource to others.
It depends a bit on the SPN you're trying to authenticate against. We do NTLM/SPNEGO authentication to HTTP servers (only), and the guidance suggests that HTTP/HTTPS server should register an SPN as http/HOSTNAME. So when we authenticate, we just prepend http/ to the upper-cased hostname. For example, we pass:
http/TFS.DOMAIN.COM
as the target to InitializeSecurityContext, where TFS.DOMAIN.COM is the upper-cased hostname that the user typed to access their TFS server.
We do not try to do any DNS lookups or FQDN matching. If the user simply types http://foo/ then our SPN is http/FOO. This means that the server admin must have configured http/FOO as an SPN.
It's not impossible that a server admin configures a machine, call it FOO and sets up the SPN http/FOO, then exposes this machine on the internet as extranet.domain.com. In that case, they should also configure http/EXTRANET.DOMAIN.COM as an SPN. This can get tricky with load balancers, etc, but this should be the server admin's responsibility.

Resources