Does JHipster support the Keycloak client resource authorization configuration? - jhipster

I have a JHipster Gateway and Microservice that are currently configured to use OAUTH/OIDC via Keycloak. Currently all resources are available to the authenticated user. I want to use the fine-grained security available in keycloak (enabling authorization on the JHipster Microservice client id) to further secure by resource id (as referenced in Keycloak documentation)
https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_server_enable_authorization. For example, restrict */api/companies/{id} to only certain Keycloak users/groups.
It this supported in Jhipster? Based on the logs, it looks like AccessControlFilter can be configured to restrict, but It's not clear to me how this connects to Keycloak fine-grained resource authentication.
2018-04-15 07:11:20.905 DEBUG 18184 --- [ XNIO-2 task-8] c.e.gateway.aop.logging.LoggingAspect : Enter: com.example.gateway.web.rest.AccountResource.getAccount() with argument[s] = [org.springframework.security.oauth2.provider.OAuth2Authentication#2ea9380c: Principal: user; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=0:0:0:0:0:0:0:1, sessionId=<SESSION>, tokenType=bearertokenValue=<TOKEN>; Granted Authorities: company.jcb.role1, ROLE_USER]
2018-04-15 07:11:20.907 DEBUG 18184 --- [ XNIO-2 task-8] c.e.gateway.aop.logging.LoggingAspect : Exit: com.example.gateway.web.rest.AccountResource.getAccount() with result = com.example.gateway.domain.User#3a45e83a
2018-04-15 07:11:22.208 DEBUG 18184 --- [oundChannel-104] c.e.g.web.websocket.ActivityService : Sending user tracking data ActivityDTO{sessionId='hchu0fkx', userLogin='user', ipAddress='/0:0:0:0:0:0:0:1:54212', page='/', time='2018-04-15T13:11:22.208Z'}
2018-04-15 07:11:24.634 DEBUG 18184 --- [ XNIO-2 task-19] c.e.g.g.a.AccessControlFilter : Access Control: allowing access for /micro/api/companies, as no access control policy has been set up for service: micro

Related

How do I get a WSE 3.0 web service to impersonate my client's identity?

I have a WSE 3.0 based web service running in Windows Server 2003 under IIS 6.0. I want the web service process to impersonate the client user that sends the web service request, however the service is not impersonating the client.
The web application has its own app pool, which is currently set to run under the Network Service identity. The Windows Server 2003 machine account has been enabled for delegation in Active Directory (at least according to my IT guy). The service WSE policy (in wse3policyCache.config) looks like this:
<policy name="GeneratedServicesPolicy">
<kerberosSecurity establishSecurityContext="false" renewExpiredSecurityContext="true" requireSignatureConfirmation="false" messageProtectionOrder="SignBeforeEncrypt" requireDerivedKeys="true" ttlInSeconds="300">
<protection>
<request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
<response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
<fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
</protection>
</kerberosSecurity>
<requireActionHeader />
</policy>
The service has the following entries (among others) in its web.config:
<identity impersonate="false"/>
<authentication mode="Windows"/>
Anonymous access is enabled for the application (this is required since transport-level security is not used by the service, message-leve is). The machine account has the following SPN's registered:
HOST/RD360-2
HOST/rd360-2.mycompany.com
The client has the following in its wse3policyCache.config:
<policy name="KerbClient">
<kerberosSecurity establishSecurityContext="false" renewExpiredSecurityContext="true" requireSignatureConfirmation="false" messageProtectionOrder="SignBeforeEncrypt" requireDerivedKeys="true" ttlInSeconds="300">
<token>
<kerberos targetPrincipal="HOST/rd360-2.mycompany.com" impersonationLevel="Impersonation" />
</token>
<protection>
<request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
<response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
<fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
</protection>
</kerberosSecurity>
<requireActionHeader />
</policy>
The client code looks like this:
static void Main(string[] args)
{
AddFloatsWSWse client = new AddFloatsWSWse();
client.SetPolicy("KerbClient");
double result = client.AddFloats(2.3, 3.2);
Console.WriteLine("Result was: '" + result + "'");
}
The service is not impersonating my client identity, though. I am using log4net in the service, and when I ask it to print out the %username into the ASP.NET trace log, it is always NT AUTHORITY\NETWORK SERVICE and not the client user id. Is there anything I'm doing wrong? Is there somewhere I can look to see if WSE is even trying to perform the impersonation and failing? I do see the following entries in my event log (MYDOMAIN and MYUSER are obscured here):
Event Type: Success Audit
Event Source: Security
Event Category: Privilege Use
Event ID: 576
Date: 12/9/2009
Time: 11:07:16 AM
User: MYDOMAIN\MYUSER
Computer: RD360-2
Description:
Special privileges assigned to new logon:
User Name: MYUSER
Domain: MYDOMAIN
Logon ID: (0x0,0x4B410AE)
Privileges: SeSecurityPrivilege
SeBackupPrivilege
SeRestorePrivilege
SeTakeOwnershipPrivilege
SeDebugPrivilege
SeSystemEnvironmentPrivilege
SeLoadDriverPrivilege
SeImpersonatePrivilege
----------------------------------------------------------------------------------
Event Type: Success Audit
Event Source: Security
Event Category: Logon/Logoff
Event ID: 540
Date: 12/9/2009
Time: 11:07:16 AM
User: MYDOMAIN\MYUSER
Computer: RD360-2
Description:
Successful Network Logon:
User Name: MYUSER
Domain: MYDOMAIN
Logon ID: (0x0,0x4B410AE)
Logon Type: 3
Logon Process: Kerberos
Authentication Package: Kerberos
Workstation Name:
Logon GUID: {OBFUSCATED}
Caller User Name: -
Caller Domain: -
Caller Logon ID: -
Caller Process ID: -
Transited Services: -
Source Network Address: -
Source Port: -
And in my WSE trace file I do see:
<processingStep description="Entering SOAP filter Microsoft.Web.Services3.Design.RequireSoapHeaderAssertion+RequireSoapHeaderFilter" />
<processingStep description="Exited SOAP filter Microsoft.Web.Services3.Design.RequireSoapHeaderAssertion+RequireSoapHeaderFilter" />
<processingStep description="Entering SOAP filter Microsoft.Web.Services3.Design.KerberosAssertion+ServiceInputFilter" />
<processingStep description="Exited SOAP filter Microsoft.Web.Services3.Design.KerberosAssertion+ServiceInputFilter" />
so at least I know the Kerberos extensions are processing my Kerberos headers.
Edit: My webservice then uses a proprietary client communication library to call into another server using SSPI/IWA (let's call this third server a foo server). I want it to use the client's identity when it makes this second call into the foo server. This means that this client communication library calls AcquireCredentialsHandle and InitializeSecurityContext using the SPN of the foo server and a different service. In this particular case, the foo server is actually running on the same machine as the WSE web service (so it's using the SPN mycompany/rd260-2). Since this second hop is to the same machine, I would expect this to use NTLM, but it still should impersonate my web service client's user identity, shouldn't it? In the logs of the foo server, I see that it accepts the connection, uses the IWA security context provided and tells me that based on this security context, the connecting user is rd36-2$ which is the machine account since the WSE web service is running in IIS under the Network Service identity (which is in turn associated to the machine account). In the logs of the foo server, after it receives the IWA security context, I ultimately want to see the identity of the user who submitted the web service request. Would it be useful to move the foo server to a different machine to see if that has some bearing on this?
The Kerberos token used with WSE 3 is a message-level security mechanism and only authenticates the client. It does not actually change the security context as in IWA, so you won't notice anything different in the trace log as such. In order to actually impersonate the client, you have to:
Enable impersonation on the security token with impersonationLevel="Impersonation" on the <kerberos> element (which you've already done); and
Have your WebMethod create a WindowsImpersonationContext based on the token's identity.
Example:
WindowsIdentity identity =
(WindowsIdentity)RequestSoapContext.Current.IdentityToken.Identity;
WindowsImpersonationContext impersonationContext = null;
try
{
impersonationContext = identity.Impersonate();
// Perform your work here
// ...
}
finally
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
As far I can understand the situation is when you're trying to make the second hop the Kerberos ticket is dropped. In double hop scenario's the Kerberos Ticket will be dropped at the second hop.
Your authentication will fail after that and will not switch to NTLM.

Ejabberd authentication with SQL and anonymous strange behaviour

After configuring ejabberd with sql authentication it works as expected, by advertising the DIGEST-MD5 and SCRAM-SHA-1 as possible authentication mechanisms.
But when I add the possibility to authenticate as anonymous it stops advertising DIGEST-MD5 and SCRAM-SHA-1 as possible auth mechanisms.
host_config:
"xmpp.example.com":
auth_method: [sql]
[debug] (tls|<0.570.0>) Send XML on stream =
<<"<stream:features>
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<mechanism>SCRAM-SHA-1</mechanism>
<mechanism>DIGEST-MD5</mechanism>
<mechanism>PLAIN</mechanism>
<mechanism>X-OAUTH2</mechanism></mechanisms>
</stream:features>">>
-
host_config:
"xmpp.example.com":
auth_method: [sql, anonymous]
[debug] (tls|<0.554.0>) Send XML on stream =
<<"<stream:features>
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<mechanism>ANONYMOUS</mechanism>
<mechanism>PLAIN</mechanism>
<mechanism>X-OAUTH2</mechanism>
</mechanisms></stream:features>">>
Currently running in docker with postgres database

Kerberos authentication ticket - Event ID 4768 - Audit failure

I am using kerberos to authenticate a user and its failing. Audit failure details in event viewer are following
A Kerberos authentication ticket (TGT) was requested.
Account Information:
Account Name: ax
Supplied Realm Name: TEST.COM
User ID: NULL SID
Service Information:
Service Name: krbtgt/TEST.COM
Service ID: NULL SID
Network Information:
Client Address: ::ffff:2.2.2.60
Client Port: 38532
Additional Information:
Ticket Options: 0x40800000
Result Code: 0x6
Ticket Encryption Type: 0xffffffff
Pre-Authentication Type: -
Certificate Information:
Certificate Issuer Name:
Certificate Serial Number:
Certificate Thumbprint:
Certificate information is only provided if a certificate was used for pre-authentication.
Pre-authentication types, ticket options, encryption types and result codes are defined in RFC 4120.
The result code 0x6 means that user doesn't exist in Kerberos database but i have a user already configured in AD.
This is windows server 2008 (non-R2) and user account name is "axtest" and User logon name is "ax/mytest". The domain name is test.com. From wireshark, i can see that my client is sending AS-REQ which has correct 2 name string items ax & mytest. I am not sure why is it failing.
I found the problem. Since i was running old Microsoft 2008 version, it was missing the hotfix (KB951191). Installing that resolved the issue.

Why is AccessTokenRequest's PreservedState perpetually null with a resultant CSRF related InvalidRequestException?

As context, I've been trying to get a fairly simple #SprintBootApplication with an additional #EnableOAuth2Sso annotation integrated with WSO2 Identity Server for quite some time now.
In my mind getting this working should be a matter of configuration (as advertised on Spring Cloud Security) - but I've had no luck thus far.
In an effort to understand what is going on I've used my debugger to step through spring-security-oauth2 code to figure out what is going on. In doing so I've noticed that my AccessTokenRequest's PreservedState is perpetually null with a resultant CSRF related InvalidRequestException. This is the relevant code:
public class AuthorizationCodeAccessTokenProvider extends OAuth2AccessTokenSupport implements AccessTokenProvider {
....
private MultiValueMap<String, String> getParametersForTokenRequest(AuthorizationCodeResourceDetails resource,
AccessTokenRequest request) {
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
form.set("grant_type", "authorization_code");
form.set("code", request.getAuthorizationCode());
Object preservedState = request.getPreservedState();
if (request.getStateKey() != null || stateMandatory) {
// The token endpoint has no use for the state so we don't send it back, but we are using it
// for CSRF detection client side...
if (preservedState == null) {
throw new InvalidRequestException(
"Possible CSRF detected - state parameter was required but no state could be found");
}
}
When it comes to the above bit of code, I'm at the point where I've approved the claim after having logged in with admin/admin and my web application has received the auth code:
http://localhost:9998/loginstate=Uu8ril&code=20ffbb6e4107ce3c5cf9ee22065f4f2
Given that all I need to do in the first instance is to get the login part working I've tried disabling CSRF, to no avail.
The relevant configuration is as follows:
spring:
profiles: default
security:
oauth2:
client:
accessTokenUri: https://localhost:9443/oauth2/token
userAuthorizationUri: https://localhost:9443/oauth2/authorize
clientId: yKSD9XwET9XJ3srGEFXP6AfHhAka
clientSecret: zuPTcdJH435h3wgl055XNZ5ffNMa
scope: openid
clientAuthenticationScheme: header
resource:
userInfoUri: https://localhost:9443/oauth2/userinfo?schema=openid
In terms of my own investigative efforts, of concern is that in the DefaultOAuthClientContext preserved state gets cleared right before it needs to used, this appears to be a sequencing issue.
DefaultAccessTokenRequest.setPreservedState(http://localhost:9998/login)
DefaultOAuth2ClientContext.state.put(avjDRM,http://localhost:9998/login)
DefaultAccessTokenRequest.setPreservedState(http://localhost:9998/login)
DefaultOAuthClientContext.state.put(MREOgG,http://localhost:9998/login)
LOGIN ON WSO2 FORM
DefaultOAuth2ClientContext.state.remove(avjDRM)
OAUth2RestTemplate…acquireAccessToken…...Object preservedState = oauth2Context.removePreservedState(avjDRM)
I'm using the latest releases of Spring Boot (1.3.0) and WSO2 Identity Server (5.0). Also using spring-security-oauth 2.0.8.
As it turns out, the reason why the cited preservedState is null in the section of code provided is because a new instance of bean Oauth2ClientContext is being created which is precisely what should not be happening - the entire purpose of the OAuth2ClientContext is to store state. In terms of the OAuth2 protocol (RFC 6749), preserving the state is important in terms of Cross-Site Request Forgery prevention (see Section 10.12).
Picking this up is a simple matter of enabling debug logging and also comparing the output generated against WSO2 IS with what one sees with a working example. In my case the working example that I always revert back to is the one provided by the Spring team themselves.
This is the client configuration (application.yml) and then log output testing using the Spring team SSO server:
spring:
profiles: default
security:
oauth2:
client:
accessTokenUri: http://192.168.0.113:32768/uaa/oauth/token
userAuthorizationUri: http://192.168.0.113:32768/uaa/oauth/authorize
clientId: acme
clientSecret: acmesecret
resource:
jwt:
keyValue: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnGp/Q5lh0P8nPL21oMMrt2RrkT9AW5jgYwLfSUnJVc9G6uR3cXRRDCjHqWU5WYwivcF180A6CWp/ireQFFBNowgc5XaA0kPpzEtgsA5YsNX7iSnUibB004iBTfU9hZ2Rbsc8cWqynT0RyN4TP1RYVSeVKvMQk4GT1r7JCEC+TNu1ELmbNwMQyzKjsfBXyIOCFU/E94ktvsTZUHF4Oq44DBylCDsS1k7/sfZC2G5EU7Oz0mhG8+Uz6MSEQHtoIi6mc8u64Rwi3Z3tscuWG2ShtsUFuNSAFNkY7LkLn+/hxLCu2bNISMaESa8dG22CIMuIeRLVcAmEWEWH5EEforTg+QIDAQAB
-----END PUBLIC KEY-----
id: openid
serviceId: ${PREFIX:}resource
Take note that there is no line mentioned the creation of OAuth2ClientContext.
DEBUG o.s.security.web.FilterChainProxy - /login?code=9HLSpP&state=G9kpy3 at position 6 of 12 in additional filter chain; firing Filter: 'OAuth2ClientAuthenticationProcessingFilter'
DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/login'; against '/login'
DEBUG o.s.s.o.c.f.OAuth2ClientAuthenticationProcessingFilter - Request is to process authentication
INFO o.s.s.o.c.DefaultOAuth2ClientContext - Getting access token request
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'scopedTarget.accessTokenRequest'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'scopedTarget.accessTokenRequest'
INFO o.s.s.o.client.OAuth2RestTemplate - Longer lived state key: G9kpy3
INFO o.s.s.o.client.OAuth2RestTemplate - Removing preserved state in oauth2context
INFO o.s.s.o.c.DefaultOAuth2ClientContext - Found preserved state: http://localhost:9999/login
This is the client configuration (application.yml) and then log output testing using WSO2IS 5.0.0:
spring:
profiles: wso2
server:
port: 9998
security:
oauth2:
client:
accessTokenUri: https://localhost:9443/oauth2/token
userAuthorizationUri: https://localhost:9443/oauth2/authorize
clientId: yKSD9XwET9XJ3srGEFXP6AfHhAka
clientSecret: zuPTcdJH435h3wgl055XNZ5ffNMa
scope: openid
clientAuthenticationScheme: header
resource:
userInfoUri: https://localhost:9443/oauth2/userinfo?schema=openid
Take note of the line with Creating instance of bean 'scopedTarget.oauth2ClientContext'.
DEBUG o.s.security.web.FilterChainProxy - /login?state=PWhQwv&code=372ff0c197a4c85a0caf070cc9a6678 at position 6 of 12 in additional filter chain; firing Filter: 'OAuth2ClientAuthenticationProcessingFilter'
DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/login'; against '/login'
DEBUG o.s.s.o.c.f.OAuth2ClientAuthenticationProcessingFilter - Request is to process authentication
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'scopedTarget.oauth2ClientContext'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2RestOperationsConfiguration$SessionScopedConfiguration$ClientContextConfiguration'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'scopedTarget.oauth2ClientContext'
INFO o.s.s.o.c.DefaultOAuth2ClientContext - Getting access token request
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'scopedTarget.accessTokenRequest'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration'
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'scopedTarget.accessTokenRequest'
INFO o.s.s.o.client.OAuth2RestTemplate - Longer lived state key: PWhQwv
INFO o.s.s.o.client.OAuth2RestTemplate - Removing preserved state in oauth2context
INFO o.s.s.o.c.DefaultOAuth2ClientContext - Found preserved state: null
Finally, the next port of call is naturally to ascertain why the OAuth2ClientContext was not created with the WSO2 IS config. Investigation has shown that it is because WSO2 IS is not passing back an expected JSESSIONID, hence the session scoped OAuth2ClientContext will not be found.
A potential hack to fix this situation if desperate is to clone Spring OAuth 2 and do the following:
In class AuthorizationCodeAccessTokenProvider do the following with the hack being to change the preserved state in the request.
private MultiValueMap<String, String> getParametersForTokenRequest(AuthorizationCodeResourceDetails resource,
AccessTokenRequest request) {
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
form.set("grant_type", "authorization_code");
form.set("code", request.getAuthorizationCode());
request.setPreservedState("http://localhost:9998/login");
Object preservedState = request.getPreservedState();
Just seen a similar issue while trying out https://spring.io/guides/tutorials/spring-boot-oauth2/
and observed that this issue is with chrome browser that wasn't passing the JSESSIONID after facebook redirect .
Same worked when I Used Safari , (just adding it here so that it saves someone's two hours !)
you can see that set-cookie is called twice as second login/facebook call is not passing previously set sessionid

WCF Identity definition in clustered environment

I apologize in advance for the length of this question, but I wanted to be sure to provide complete information as I have been researching it for weeks.
As a followup to this question on WCF authorization errors, I'm trying to determine how to specify the SPN (or should this be a UPN?) for the service.
My issue is currently that when attempting to contact the service I go through a load balancer. The load balancer alternately sends me to one of two servers, svcserv1 or svcserv2. I have not specified anything beyond the load balancer domain name in my service code, yet when the application connects to one server it is fine and the other always fails authentication.
After turning on Kerberos logging, this is a snippet from svcserv1 (a virtual server) which shows the success. Note that this success is referencing the second server (svcserv2), which is a physical server.
Logon attempt using explicit credentials:
Logged on user:
User Name: jsweb
Domain: DOMAIN
Logon ID: (0x0,0x6278B2DA)
Logon GUID: {ca6e029d-4073-3f85-5ff5-16514b9acc03}
User whose credentials were used:
Target User Name: jsweb
Target Domain:
Target Logon GUID: -
Target Server Name: svcserv2.domain.com
Target Server Info: svcserv2.domain.com
Caller Process ID: 6680
Source Network Address: -
Source Port: -
The failure is when communicating with svcserv1 and is as follows:
Logon attempt using explicit credentials:
Logged on user:
User Name: jsweb
Domain: DOMAIN
Logon ID: (0x0,0x6278B2DA)
Logon GUID: {ca6e029d-4073-3f85-5ff5-16514b9acc03}
User whose credentials were used:
Target User Name: jsweb
Target Domain:
Target Logon GUID: -
Target Server Name: svcserv1.domain.com
Target Server Info: svcserv1.domain.com
Caller Process ID: 6680
Source Network Address: -
Source Port: -
Logon Failure:
Reason: An error occurred during logon
User Name: jsweb
Domain:
Logon Type: 3
Logon Process: ˜]
Authentication Package: NTLM
Workstation Name: SVCSERV1
Status code: 0xC000006D
Substatus code: 0x0
Caller User Name: -
Caller Domain: -
Caller Logon ID: -
Caller Process ID: -
Transited Services: -
Source Network Address: 10.1.36.80
Source Port: 56078
The 'Logon Failure' response appears in the event viewer from user 'NT AUTHORITY\SYSTEM' so I'm assuming this is who the service is running as. The jsweb id (above) is set up in the web.config as the impersonating identity: <identity impersonate="true" userName="DOMAIN\jsweb" password="password"/>
For this reason it seems to me that it should be generating an SPN (host/hostname) but in the case of a clustered environment it makes more sense that a UPN (username#domainName) should be generated. Sorry if I can't be more specific here. Is there a way for me to see which is being expected/transmitted? This article states that "If you set the SPN or UPN equal to an empty string, a number of different things happen, depending on the security level and authentication mode being used. If you are using transport level security, NT LanMan (NTLM) authentication is chosen." Since I am using
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
and, apparently?, the SPN is blank, then it is defaulting to NTLM. This can be seen in the failure output above next to 'Authentication Package'.
Further referencing MSDN indicates that "When you use NT LanMan (NTLM) for authentication, the service identity is not checked because, under NTLM, the client is unable to authenticate the server." So this explains the issue, but I have not been able to determine the solution. I have not specified the <identity> for the endpoint but have tried to use the clustered domain name ...
<endpoint>
<identity>
<dns value="svcserv"/>
</identity>
</endpoint>
...but this has not worked.
I did find this disappointing Microsoft knowledgebase article titled, 'Authentication delegation through Kerberos does not work in load-balanced architectures' but I have to believe that it is possible since the use of a load balancer is not unusual.
Perhaps I am chasing my own tail since in 'Setting up Kerberos Authentication against the cluster name Service Principal Name' (specifically Phase 3: Administration of Client) it is stated that "There are really no special steps to be performed at the client. The client computer has to use the SPN registered on the domain user account" so am I at the mercy of the server admin team?
Thanks for any help and feel free to ask for clarification.

Resources