OpenID Connect

Weavy has support for OpenID Connect. OpenID Connect is a simple identity layer built on top of the OAuth 2.0 protocol and is an increasingly common authentication protocol: when an app prompts you to authenticate using your Facebook or Google credentials, the app is probably using OpenID Connect.

Many large identity providers such as Microsoft, Facebook, Google, Okta and OneLogin support OpenID Connect which makes it easy to configure Weavy to use them as identity providers.

Configuration

The following settings are required for Weavy to use authentication with OpenID.

Web server

The Weavy website in IIS must be configured with the following settings:

Anonymous Authentication = Enabled
Forms Authentication = Disabled
Windows Authentication = Disabled

Web.config

The web.config file should have the following configuration:

<system.web>
    <authentication mode="None" />
</system.web>

Startup Configuration

Additionally you must add some code to the Startup.cs file located in the App_Start folder. The exact code required to configure OpenID Connect depends on the the provider, but since they all implement the OpenID Connect specification the code is generally pretty similar.

For the examples below you will also need to install the Microsoft.Owin.Security.OpenIdConnect Nuget package (if you don't have it already).

Azure Active Directory

First step in configuring Azure AD authentication is registering your application in the Azure portal. See Add sign-in with Microsoft to an ASP.NET web app for more details.

Once you have the ClientId and TenantId you should add them to your web.config file.

<appSettings>
    <!-- the application id for the app you registered -->
    <add key="AzureClientId" value="..." />
     <!-- the tenant id for your organization -->
    <add key="AzureTenantId" value="..." />
</appSettings>

Next you should add the following code to the Startup.cs file:

public partial class Startup {

    public void Configuration(IAppBuilder app) {
        app.UseWeavy();

        var azureClientId = ConfigurationManager.AppSettings["AzureClientId"];
        var azureTenantId = ConfigurationManager.AppSettings["AzureTenantId"];
        if (azureClientId != null && azureTenantId != null) {
            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions {
                AuthenticationType = "Azure",
                AuthenticationMode = AuthenticationMode.Passive,
                Authority = $"https://login.microsoftonline.com/{azureTenantId}/v2.0",
                Caption = "Azure AD",
                ClientId = azureClientId,
                Notifications = new OpenIdConnectAuthenticationNotifications() {
                    RedirectToIdentityProvider = (context) => {
                        // this ensures that the address used for sign in and sign out is picked up dynamically (it must still be registered in the Azure portal)
                        context.ProtocolMessage.RedirectUri = WeavyContext.Current.ApplicationUrl;
                        return Task.CompletedTask;
                    },
                    SecurityTokenValidated = (context) => {
                        // add authentication_type claim
                        context.AuthenticationTicket.Identity.AddClaim(new Claim("authentication_type", context.Options.AuthenticationType, null, LoginService.LOCAL_AUTHENTICATION_TYPE));
                        return Task.CompletedTask;
                    },
                    AuthenticationFailed = (context) => {
                        context.OwinContext.Response.Redirect(WeavyContext.Current.ApplicationPath + "error/unauthorized");
                        context.HandleResponse();
                        return Task.CompletedTask;
                    }
                },
                Scope = "openid email profile",
            });
        }
    }
}

And that's it, Weavy will now display a button on the sign in page allowing your users to authenticate against your Azyre Active Directory.

Google OpenID Connect

First step in configuring the Google OpenID provider is registering your application in the Google API Console. See Google Identity Platform for detailed instructions.

When asked to enter an authorized redirect URI you should enter the url to your weavy instance followed by /sign-in-callback, .e.g. https://www.example.com/sign-in-callback.

Once you have the ClientId and ClientSecret you should add them to your web.config.

<appSettings>
    <!-- the application id for the app you registered -->
    <add key="GoogleClientId" value="..." />
     <!-- the clietn secret for the app you registered -->
    <add key="GoogleClientSecret" value="..." />
    <!-- the domain for your organization, e.g. example.com -->
    <add key="GoogleDomain" value="..." /> 
</appSettings>

Next you need to add the following code to the Startup.cs file:

public partial class Startup {

    public void Configuration(IAppBuilder app) {
        app.UseWeavy();

        var googleClientId = ConfigurationManager.AppSettings["GoogleClientID"];
        var googleClientSecret = ConfigurationManager.AppSettings["GoogleClientSecret"];
        var googleDomain = ConfigurationManager.AppSettings["GoogleDomain"];
        if (googleClientId != null && googleClientSecret != null && googleDomain != null) {
            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions {
                AuthenticationType = "Google",
                AuthenticationMode = AuthenticationMode.Passive,
                Authority = "https://accounts.google.com",
                Caption = "Google",
                ClientId = googleClientId,
                ClientSecret = googleClientSecret,
                Notifications = new OpenIdConnectAuthenticationNotifications() {
                    RedirectToIdentityProvider = (context) => {
                        // this ensures that the address used for sign in and sign out is picked up dynamically (it must still be registered in the Google developer console)
                        context.ProtocolMessage.RedirectUri = WeavyContext.Current.ApplicationUrl + "signin-google";

                        // set the hd parameter to optimize the OpenID Connect flow for users of the specified domain.  
                        context.ProtocolMessage.Parameters.Add("hd", googleDomain);

                        return Task.CompletedTask;
                    },
                    SecurityTokenValidated = (context) => {
                        // validate domain
                        string hd = context.AuthenticationTicket.Identity.FindFirst("hd")?.Value;
                        if (hd == null) {
                            throw new SecurityTokenValidationException("No hosted domain (hd) found in claims.");
                        } else if (!hd.Equals(googleDomain, StringComparison.OrdinalIgnoreCase)) {
                            throw new SecurityTokenValidationException($"Hosted domain {hd} is not allowed.");
                        }

                        // add authentication_type claim
                        context.AuthenticationTicket.Identity.AddClaim(new Claim("authentication_type", context.Options.AuthenticationType, null, LoginService.LOCAL_AUTHENTICATION_TYPE));
                        return Task.CompletedTask;
                    },
                    AuthenticationFailed = (context) => {
                        context.OwinContext.Response.Redirect(WeavyContext.Current.ApplicationPath + "error/unauthorized");
                        context.HandleResponse();
                        return Task.CompletedTask;
                    }
                },
                Scope = "openid email profile",
            });
        }
    }
}

And that's it, Weavy will now display a button on the sign in page allowing your users to authenticate against your Google Apps user directory.