Search code examples
c#asp.net-mvcazureowinowin-middleware

How can I use OWIN Authentication with Microsoft account?


Currently I am using OWIN authentication in my application. I am using Tenant as common. So, it is authenticating any user from azure active directory as well as Microsoft account.

I want to restrict user only for Microsoft account.

Below is my web.config file

<add key="ClientId" value="<client id>" />
<add key="RedirectUri" value="https://localhost:44384/" />
<add key="Tenant" value="common" />
<add key="Authority" value="https://login.microsoftonline.com/{0}/v2.0" />

code from Startup.cs

public class Startup
{
    // The Client ID is used by the application to uniquely identify itself 
    //to Azure AD.

    string clientId =  
System.Configuration.ConfigurationManager.AppSettings["ClientId"];

    // RedirectUri is the URL where the user will be redirected to after 
    //they sign in.
    string redirectUri = 
    System.Configuration.ConfigurationManager.AppSettings["RedirectUri"];

    // Tenant is the tenant ID (e.g. contoso.onmicrosoft.com, or 'common' 
    //for multi-tenant)
    static string tenant = 
    System.Configuration.ConfigurationManager.AppSettings["Tenant"];

    // Authority is the URL for authority, composed by Azure Active 
    //Directory v2 endpoint and the tenant name (e.g. 
    //https://login.microsoftonline.com/contoso.onmicrosoft.com/v2.0)

    string authority = 
    String.Format(System.Globalization.CultureInfo.InvariantCulture, 
    System.Configuration.ConfigurationManager.AppSettings["Authority"], 
    tenant);

    /// <summary>
    /// Configure OWIN to use OpenIdConnect 
    /// </summary>
    /// <param name="app"></param>
    public void Configuration(IAppBuilder app)
    {
    app.SetDefaultSignInAsAuthenticationType
    (CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions());

        //app.UseMicrosoftAccountAuthentication(clientId: "", clientSecret: 
   "");

        app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
                // Sets the ClientId, authority, RedirectUri as obtained 
                //from web.config
                ClientId = clientId,
            Authority = authority,
            RedirectUri = redirectUri,
                // PostLogoutRedirectUri is the page that users will be 
     //redirected to after sign-out. In this case, it is using the home page
                PostLogoutRedirectUri = redirectUri,
            Scope = OpenIdConnectScopes.OpenIdProfile,
                // ResponseType is set to request the id_token - which 
   //contains basic information about the signed-in user
                ResponseType = OpenIdConnectResponseTypes.IdToken,
                // ValidateIssuer set to false to allow personal and work accounts from any organization to sign in to your application
                // To only allow users from a single organizations, set ValidateIssuer to true and 'tenant' setting in web.config to the tenant name
                // To allow users from only a list of specific organizations, set ValidateIssuer to true and use ValidIssuers parameter 
                TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = false },
                // OpenIdConnectAuthenticationNotifications configures OWIN 
  //to send notification of failed authentications to OnAuthenticationFailed 
 //method
                Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = OnAuthenticationFailed
            }
        }
    );

    }

    /// <summary>
    /// Handle failed authentication requests by redirecting the user to the 
    //home page with an error in the query string
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>

 private Task OnAuthenticationFailed
 (AuthenticationFailedNotification<OpenIdConnectMessage, 
 OpenIdConnectAuthenticationOptions> context)
    {
        context.HandleResponse();
        context.Response.Redirect("/?errormessage=" + 
        context.Exception.Message);
        return Task.FromResult(0);
    }
}

How Can I restrict only for Microsoft authentication(for user '[email protected]')?


Solution

  • To allows only users with personal Microsoft accounts (MSA) to sign into the application, we need to use consumers instead of common as the value of tenant in the authority.

    More detailed about this parameters, please refer the link below:

    v2.0 Protocols - OAuth 2.0 Authorization Code Flow

    Update

    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            // The `Authority` represents the v2.0 endpoint - https://login.microsoftonline.com/common/v2.0
            // The `Scope` describes the initial permissions that your app will need.  See https://azure.microsoft.com/documentation/articles/active-directory-v2-scopes/                    
            ClientId = clientId,
            //Authority = String.Format(CultureInfo.InvariantCulture, aadInstance, "adnewfei.onmicrosoft.com", "/v2.0"),
            Authority = String.Format(CultureInfo.InvariantCulture, aadInstance, "common", "/v2.0"),
            RedirectUri = redirectUri,
            Scope = "openid email profile offline_access Mail.Read User.Read",
            PostLogoutRedirectUri = redirectUri,
            TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = false,
    
            },
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                // If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
                AuthorizationCodeReceived = async (context) =>
                {
                    var code = context.Code;
                    string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
                    ConfidentialClientApplication cca = new ConfidentialClientApplication(clientId, redirectUri,
                       new ClientCredential(appKey),
                       new MSALSessionCache(signedInUserID, context.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase));
                    string[] scopes = { "Mail.Read User.Read" };
                    try
                    {
                        AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(scopes, code);
                    }
                    catch (Exception eee)
                    {
    
                    }
                },
                AuthenticationFailed = (notification) =>
                {
                    notification.HandleResponse();
                    notification.Response.Redirect("/Error?message=" + notification.Exception.Message);
                    return Task.FromResult(0);
                },
                SecurityTokenValidated = (context) => {
                    if (context.AuthenticationTicket.Identity.Claims.First(claim => claim.Type == "preferred_username").Value == "[email protected]")
                    {
    
                    }
                    else
                    {
                        throw new System.IdentityModel.Tokens.SecurityTokenValidationException();
                    }
                    return Task.FromResult(0);
                },
            },
        });