4

Please tell me what is wrong.

    public void ConfigureAuth(IAppBuilder app)
    {
        var mo = new MicrosoftAccountAuthenticationOptions();
        mo.ClientId = "xxxxxxxxxxxxxxxxx";
        mo.ClientSecret = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";
        mo.Scope.Add("wl.basic"); // No effect if this commented out
        mo.Scope.Add("wl.emails");

        // IF I COMMENT NEXT TWO PROPERTIES, USER IS AUTHENTICATED, BUT THE DB IS NOT
        // UPDATED. LEAVE THEM AND THE REDIRECT FROM MSLIVE ENDS ON LOGIN PAGE

        mo.SignInAsAuthenticationType = "External";
        mo.Provider = new MicrosoftAccountAuthenticationProvider()
        {
            OnAuthenticated = (context) =>
                {
         // Set breakpoint here to see the context.Identity.Claims HAS CLAIMS DESIRED.
         // SO IT APPEARS TO ME Nothing to do here but verify they exist in the debugger.
         //(context.Identity.Claims).Items  ARE:  
         //{http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: xxxxxxxxx}
         //{http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: yyyy yyyyy} 
         //{urn:microsoftaccount:id: xxxxxxxx}  
         //{urn:microsoftaccount:name: yyyy yyyyy}  
         //{http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: xxxxxxxx@hotmail.com}
                return Task.FromResult(0);
                }
        };
        // Enable the application to use a cookie to store information for the signed in user
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")
        });
        // Use a cookie to temporarily store information about a user logging in with a third party login provider
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        app.UseMicrosoftAccountAuthentication(mo);
    }

A reasonable expectation asserts that the framwework will transparently handle the addition of a Scope to the default *AuthenticationOptions. Subsequently, wrt the MVC5 template, the developer can extract and persist Claims in ExternalLoginConfirmation code. Another reasonable expectation is that the framework will transform incoming standard ClaimTypes into Claims in the ClaimsIdentity exposed by the framework.

I am very glad source code is available MicrosoftAccountAutheticationHandler.cs, and I will check it to solve this; lacking a response. Best wishes to Katana as the documentation and the framework are maturing. Is there a way for the framework to help the developer spot config issues?.

subsci
  • 1,740
  • 17
  • 36

1 Answers1

0

I would have agreed with you if we both had not hit the same logical brick wall of reasonning .... I think it is something to do with a detached Owin Security Context while the web application operates in a seperate Context and you have to 'seed' the web one. So what I've deduced is this:

in Startup.Auth.cs

var microsoftOptions =
            new Microsoft.Owin.Security.MicrosoftAccount.MicrosoftAccountAuthenticationOptions
            {
                CallbackPath = new Microsoft.Owin.PathString("/Callbacks/External"),//register at oAuth provider
                ClientId = "xxxx",
                ClientSecret = "yyyyyyyyyyyyyyyyy",
                Provider = new Microsoft.Owin.Security.MicrosoftAccount.MicrosoftAccountAuthenticationProvider
                {
                    OnAuthenticated = (context) =>
                        {
                            context.Identity.AddClaim(new Claim(providerKey, context.Identity.AuthenticationType));
                            context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.Identity.FindFirstValue(ClaimTypes.Name)));
                            return System.Threading.Tasks.Task.FromResult(0);
                        }
                }
            };
        microsoftOptions.Scope.Add("wl.basic");
        microsoftOptions.Scope.Add("wl.emails");
        app.UseMicrosoftAccountAuthentication(microsoftOptions);

and in AccountController:

    [AllowAnonymous]
    public async Task<ActionResult> oAuthCallback(string returnUrl)
    {
        var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
        if (loginInfo == null)
        {
            if (User.Identity.IsAuthenticated)
                return RedirectToAction("Index", "Manage");
            else
                return RedirectToAction("Login");
        }

        var currentUser = await UserManager.FindAsync(loginInfo.Login);
        if (currentUser != null)
        {
            await StoreExternalTokensOnLocalContext(currentUser);
        }
        //.... rest as same as per AspNet Sample project.
    }


    private async Task StoreExternalTokensOnLocalContext(ApplicationUser user)
    {
        if (user == null)
            return;

        var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
        if (externalIdentity != null)
        {
            // Retrieve the existing claims for the user and add the FacebookAccessTokenClaim 
            var currentClaims = await UserManager.GetClaimsAsync(user.Id);
            //var providerClaim = externalIdentity.FindFirstValue("provider") ?? string.Empty;
            await StoreClaim("provider", user.Id, externalIdentity);
            await StoreClaim("FacebookId", user.Id, externalIdentity);
            await StoreClaim("image", user.Id, externalIdentity);
            await StoreClaim("link", user.Id, externalIdentity);
            await StoreClaim(ClaimTypes.Name, user.Id, externalIdentity);
            await StoreClaim(ClaimTypes.Email, user.Id, externalIdentity);

            var addedClaims = await UserManager.GetClaimsAsync(user.Id);
        }
    }

    private async Task StoreClaim(string typeName, string userId, ClaimsIdentity externalIdentity)
    {
        var providerClaim = externalIdentity.Claims.FirstOrDefault(c => c.Type.Equals(typeName));
        if (providerClaim == null)
            return;
        var previousClaims = await UserManager.GetClaimsAsync(userId);
        if (previousClaims.IndexOf(providerClaim) >= 0)
            return;
        var idResult = await UserManager.AddClaimAsync(userId, providerClaim);
    }
D4rkTiger
  • 352
  • 1
  • 13
OzBob
  • 4,227
  • 1
  • 39
  • 48