12

I have a SharePoint (2010) on-premises, plugged to an ADFS server. I deploy custom components (Web parts, _layouts pages) with custom code onto it.

One of these components must access data stored in an Exchange Online (Office 365) for the current user, like last emails and calendar events.
I'm trying to get this done from the server-side code hosted in my SharePoint. SharePoint and Office 365 are both connected to the same on-prem ADFS.

The following diagram shows the situation:

enter image description here

I cannot find any information on how to code the access delegation to the Exchange Online.

Is there any code sample, tutorial or at least some hints on how to get access to the Exchange data on-behalf of the current user in this situation?
i.e. delegating credentials from SharePoint on-prem (ADFS) to Exchange Online API (same ADFS)?

As the user has already logged on the on-prem SharePoint (via ADFS), I don't want her/him to logon again or to give consent for a third-party app (thus excluding Graph API?).

  • How can I get the correct "token" from ADFS while running server-side code on the SharePoint side, and then use it to get a token from Office 365?
  • What API can I use to get the correct Office 365 "token" to authenticate the Exchange API request?
  • What Exchange API can I use? EWS ? REST?

Notes:

  • after running some tests, I'm quite confident we can replace "SharePoint" by "any ASP.NET app" in my question.
  • if there's at least a "simple" solution all client-side, I could settle for it.
  • 1
    Using the Graph? graph.microsoft.io/en-us/docs – Eric Alexander Jan 10 '17 at 19:03
  • Hi Eric, thank you for your input. I'm not sue the Graph API can solve all the problems I have here, but still have to clarify a lot. Don't you think this question would be better on SO? If so, can you please migrate it? – Evariste Jan 11 '17 at 13:18
3

You can use one of ADFS features called ActAs.
When user is authenticated with ADFS in some ASP.NET application, usually there is a "BootstrapToken":

((IClaimsIdentity)Thread.CurrentPrincipal.Identity).BootstrapToken; 

holding security bits about authenticated user. Using ActAs feature you can request new token for another relying party, which accepts ADFS authentication.
The tricky part is that "some ASP.NET application" is your SharePoint and "another relying party" is Exchange Online.

Theoretically, in your serer side code, you can do something like this:

var userToken = ((IClaimsIdentity)Thread.CurrentPrincipal.Identity).BootstrapToken;

var token = GetActAsToken(userToken);

var client = new HttpClient
{
    BaseAddress = _baseAddress
};

client.SetToken("SAML", token.TokenXml.OuterXml);
var response = client.GetAsync("exchange api").Result;
// or attach token to EWS somehow

private SecurityToken GetActAsToken(SecurityToken bootstrapToken)
{
    var factory = new WSTrustChannelFactory(
        new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
        new EndpointAddress(_stsAddress));
    factory.TrustVersion = TrustVersion.WSTrust13;
 //some "service account" required in order to issue "act as" tokens
    factory.Credentials.UserName.UserName = "middletier";
    factory.Credentials.UserName.Password = "abc!123";

    var rst = new RequestSecurityToken
    {
        AppliesTo = new EndpointAddress(_serviceAddress),

        RequestType = RequestTypes.Issue,
        KeyType = KeyTypes.Symmetric,
        ActAs = new SecurityTokenElement(bootstrapToken)
    };

    var channel = factory.CreateChannel();
    var delegationToken = channel.Issue(rst);

    return delegationToken;
}

Honestly, never tried this, just some points to think, google and try for you.

Some links:

pass-adfs-token-to-a-service
Requesting Delegation (ActAs) Tokens using WSTrustChannel
Delegating secure tokens from one relying party to another
Identity Delegation with AD FS 2.0 Step-by-Step Guide
ebservices-adfs-actas

  • Hi Kai. Thank you for these inputs! I'm not sure if I can go with that, but surely I'll give this approach a try! I'll let you know, thanks again. – Evariste Jan 11 '17 at 13:25
  • 1
    You are welcome :) The question is really interesting, if you find an exact solution, please provide your answer and ping me here in comments :) – Sergei Sergeev Jan 11 '17 at 13:29
  • I tried everything server-side, including a lot of variations of your code Sergei. However, I cannot get a valid token for Office365 by simply passing the bootstrap token, even if I hard-code the authentication to ADFS as you do in your code (and I don't want to hard-code any credentials). Maybe a configuration "problem" on the ADFS-side, but never find a clue. Not to mention I don't know how to request the Exchange Online API if I finally succeeded in retrieving a valid token... I'll now focus my efforts on a client-side approach, even if it's not ideal in my case. – Evariste Feb 6 '17 at 10:23
  • I finally implemented a client-side solution based on msdn.microsoft.com/en-us/office/office365/howto/…. I had to adapt it to redirect properly and handle the token expiration, but it kinda works. Most important drawback is all the redirections happening when the user navigates to the page containing my widget. – Evariste Mar 18 '17 at 18:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.