I'm trying to achieve this scenario (I'm developing the SharePoint Web part in C#, server-side):
i.e. I'm aiming at delegating the credentials of the initial user (connecting to SharePoint) to a back-end system made of an Exchange Online (Office 365) mailbox, using a-yet--to-be-determined API (EWS or else).
Both SharePoint (on-prem) and Exchange Online are connected to the same ADFS.
First step is to get a new token from ADFS (then I'll get from Office 365 another token in from the one given by ADFS, and then I'll use the O365 token to call the Exchange Online API... unless I'm wrong here?).
In a word, I want to get a new token for the current user based on the "bootstraptoken" in use for the current connection.
Here's the initial code I have:
public static System.IdentityModel.Tokens.SecurityToken GetDelegationToken()
{
IClaimsPrincipal claimsPrincipal = Thread.CurrentPrincipal as IClaimsPrincipal;
SecurityToken bootstrapToken = claimsPrincipal.Identities[0].BootstrapToken;
WS2007HttpBinding binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential);
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.ClientCredentialType = MessageCredentialType.IssuedToken;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
WSTrustChannelFactory factory = new WSTrustChannelFactory(binding, new EndpointAddress(c_adfsBaseUrl + "adfs/services/trust/13/usernamemixed"));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.SupportInteractive = false;
RequestSecurityToken rst = new RequestSecurityToken
{
RequestType = WSTrust13Constants.RequestTypes.Issue,
AppliesTo = new EndpointAddress(c_realm),
KeyType = WSTrust13Constants.KeyTypes.Bearer,
TokenType = "urn:oasis:names:tc:SAML:2.0:assertion",
};
factory.ConfigureChannelFactory();
IWSTrustChannelContract channel = factory.CreateChannelWithIssuedToken(bootstrapToken);
RequestSecurityTokenResponse rstr;
SecurityToken token = channel.Issue(rst, out rstr);
return token;
}
This fails on channel.Issue
with:
The signing token System.IdentityModel.Tokens.SamlSecurityToken has no keys. The security token is used in a context that requires it to perform cryptographic operations, but the token contains no cryptographic keys. Either the token type does not support cryptographic operations, or the particular token instance does not contain cryptographic keys. Check your configuration to ensure that cryptographically disabled token types (for example, UserNameSecurityToken) are not specified in a context that requires cryptographic operations (for example, an endorsing supporting token).
I then followed the suggestion made by Travis Spencer here. I ended up with that code:
public static System.IdentityModel.Tokens.SecurityToken GetDelegationToken()
{
IClaimsPrincipal claimsPrincipal = Thread.CurrentPrincipal as IClaimsPrincipal;
SecurityToken bootstrapToken = claimsPrincipal.Identities[0].BootstrapToken;
WS2007FederationHttpBinding binding = new WS2007FederationHttpBinding(WSFederationHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Message.NegotiateServiceCredential = false;
binding.Security.Message.IssuedKeyType = SecurityKeyType.BearerKey;
/*
WS2007HttpBinding binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential);
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.ClientCredentialType = MessageCredentialType.IssuedToken;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
*/
WSTrustChannelFactory factory = new WSTrustChannelFactory(binding, new EndpointAddress(c_adfsBaseUrl + "adfs/services/trust/13/usernamemixed"));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.SupportInteractive = false;
RequestSecurityToken rst = new RequestSecurityToken
{
RequestType = WSTrust13Constants.RequestTypes.Issue,
AppliesTo = new EndpointAddress(c_realm),
KeyType = WSTrust13Constants.KeyTypes.Bearer,
TokenType = "urn:oasis:names:tc:SAML:2.0:assertion",
};
factory.ConfigureChannelFactory();
IWSTrustChannelContract channel = factory.CreateChannelWithIssuedToken(bootstrapToken);
RequestSecurityTokenResponse rstr;
SecurityToken token = channel.Issue(rst, out rstr);
return token;
}
But now it fails with:
An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.
And inner message:
An error occurred when processing the security tokens in the message.
What can I try next?
How to get a new token to access Office 365 while the user is already logged-on via my ADFS?