Authenticate Office 365 users with Microsoft Dynamics CRM Online web services

 

Applies To: Dynamics CRM 2013

This topic applies to customers who access Microsoft Dynamics CRM Online through the Microsoft Online Services environment. There are multiple Microsoft Dynamics CRM Online identity providers that must be accounted for when you develop an application that connects to the Organization or Discovery web services. These providers can be identified as managed domain, federated, and Microsoft account (formerly Windows Live ID). This topic focuses on Microsoft Dynamics CRM Online web service authentication with managed domain and federated identity providers, although the same classes and code shown here also work with all supported identity providers and Microsoft Dynamics CRM deployment types.

In This Topic

Use the simplified authentication classes

Authenticate Microsoft account users with Office 365

Authentication deep dive

Use the simplified authentication classes

You can use the OrganizationServiceProxy and DiscoveryServiceProxy classes when authenticating with the web services. For more information about using these proxy classes see Authentication by using the client proxy classes.

Another authentication approach uses the CrmConnection class. With just a few lines of code, your application can authenticate with the web services and start calling web methods. For more information about the CrmConnection class, see Simplified connection to Microsoft Dynamics CRM 2013. Sample code is available in the Sample: Simplified connection quick start using Microsoft Dynamics CRM 2013 topic.

CrmConnection connection = CrmConnection.Parse (connectionString);
using ( OrganizationService orgService = new OrganizationService(connection)) { }

Another authentication approach is to use the helper source code provided in the SDK. The ServerConnection helper class, shown in the Helper code: ServerConnection class topic, provides GetOrganizationProxy and GetProxy methods for authentication. If you look at the source code for ServerConnection, you will see that GetOrganizationProxy actually calls GetProxy.

using ( OrganizationServiceProxy orgServiceProxy = ServerConnection.GetOrganizationProxy(serverConfig) ) { }

You must create these organization or discovery service proxy objects in a using statement to correctly dispose of the service proxy, or call Dispose directly. For sample code that uses the GetOrganizationProxy helper code method, see Sample: Quick start for Microsoft Dynamics CRM 2013.

The complete list of authentication classes available in the Microsoft Dynamics CRM SDK is shown in the Authentication classes section.

Authenticate Microsoft account users with Office 365

Your application needs to support those Microsoft Dynamics CRM Online users whose organization is transitioned from the Microsoft account identity provider to the Microsoft Online Services identity provider. In this scenario, users may provide their Microsoft account logon credentials when they authenticate with the Microsoft Online Services identity provider of Microsoft Dynamics CRM Online.

To do this, pass the populated logon credentials in the OrganizationServiceProxy constructor or the Authenticate method of the IServiceManagement class. The credential values are populated as follows:

AuthenticationCredentials.ClientCredentials = <Microsoft account logon credentials>
AuthenticationCredentials.SupportingCredentials.ClientCredentials = <device credentials>

You can obtain the device credentials by using one of the public methods, for example LoadOrRegister, in the DeviceIdManager helper code. For more information see Helper code: DeviceIdManager class.

If your code checks the identity provider type to determine how to authenticate, then additional code is required. See the GetCredentials method in the next section for sample code that supports transitioned Microsoft account users.

For more information about this transition, see Microsoft Dynamics CRM Online Integration with Office 365.

Authentication deep dive

The previous discussion introduced two simple approaches that can be used to authenticate a user with the Microsoft Dynamics CRM web services. The following information shows how to authenticate a user by using the IServiceManagement<TService> class and includes the source code to the GetProxy method. To see the complete sample that contains the following examples, see Sample: Authenticate users with Microsoft Dynamics CRM 2013 web services. You will notice that authentication at this level takes a lot more code.

The following sample code demonstrates the classes and methods that you can use in your application to authenticate an Office 365/MOS user using the Microsoft Dynamics CRM Online web services.


IServiceManagement<IOrganizationService> orgServiceManagement =
    ServiceConfigurationFactory.CreateManagement<IOrganizationService>(
    new Uri(organizationUri));

// Set the credentials.
AuthenticationCredentials credentials = GetCredentials(orgServiceManagement, endpointType);

// Get the organization service proxy.
using (OrganizationServiceProxy organizationProxy =
    GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials))
{
    // This statement is required to enable early-bound type support.
    organizationProxy.EnableProxyTypes();

    // Now make an SDK call with the organization service proxy.
    // Display information about the logged on user.
    Guid userid = ((WhoAmIResponse)organizationProxy.Execute(
        new WhoAmIRequest())).UserId;
    SystemUser systemUser = organizationProxy.Retrieve("systemuser", userid,
        new ColumnSet(new string[] { "firstname", "lastname" })).ToEntity<SystemUser>();
    Console.WriteLine("Logged on user is {0} {1}.",
        systemUser.FirstName, systemUser.LastName);
}

Dim orgServiceManagement As IServiceManagement(Of IOrganizationService) =
    ServiceConfigurationFactory.CreateManagement(Of IOrganizationService)(New Uri(organizationUri))

' Set the credentials.
Dim credentials As AuthenticationCredentials = GetCredentials(serviceManagement, endpointType_renamed)

' Get the organization service proxy.
Using organizationProxy As OrganizationServiceProxy =
    GetProxy(Of IOrganizationService, OrganizationServiceProxy)(orgServiceManagement, credentials)
    ' This statement is required to enable early-bound type support.
    organizationProxy.EnableProxyTypes()

    ' Now make an SDK call with the organization service proxy.
    ' Display information about the logged on user.
    Dim userid As Guid = (CType(organizationProxy.Execute(New WhoAmIRequest()), 
                          WhoAmIResponse)).UserId
    Dim systemUser_renamed As SystemUser =
        organizationProxy.Retrieve("systemuser",
                                   userid,
                                   New ColumnSet(New String() {"firstname",
                                                               "lastname"})).ToEntity(Of SystemUser)()
    Console.WriteLine("Logged on user is {0} {1}.",
                      systemUser_renamed.FirstName, systemUser_renamed.LastName)
End Using

The code creates an IServiceManagement<TService> object for the Organization service. An object of type AuthenticationCredentials is used to contain the user’s logon credentials. The IServiceManagement object and user credentials are then passed to GetProxy to obtain the web service proxy reference.


/// <summary>
/// Obtain the AuthenticationCredentials based on AuthenticationProviderType.
/// </summary>
/// <param name="service">A service management object.</param>
/// <param name="endpointType">An AuthenticationProviderType of the CRM environment.</param>
/// <returns>Get filled credentials.</returns>
private AuthenticationCredentials GetCredentials<TService>(IServiceManagement<TService> service, AuthenticationProviderType endpointType)
{
    AuthenticationCredentials authCredentials = new AuthenticationCredentials();

    switch (endpointType)
    {
        case AuthenticationProviderType.ActiveDirectory:
            authCredentials.ClientCredentials.Windows.ClientCredential =
                new System.Net.NetworkCredential(_userName,
                    _password,
                    _domain);
            break;
        case AuthenticationProviderType.LiveId:
            authCredentials.ClientCredentials.UserName.UserName = _userName;
            authCredentials.ClientCredentials.UserName.Password = _password;
            authCredentials.SupportingCredentials = new AuthenticationCredentials();
            authCredentials.SupportingCredentials.ClientCredentials =
                Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice();
            break;
        default: // For Federated and OnlineFederated environments.                    
            authCredentials.ClientCredentials.UserName.UserName = _userName;
            authCredentials.ClientCredentials.UserName.Password = _password;
            // For OnlineFederated single-sign on, you could just use current UserPrincipalName instead of passing user name and password.
            // authCredentials.UserPrincipalName = UserPrincipal.Current.UserPrincipalName;  // Windows Kerberos

            // The service is configured for User Id authentication, but the user might provide Microsoft
            // account credentials. If so, the supporting credentials must contain the device credentials.
            if (endpointType == AuthenticationProviderType.OnlineFederation)
            {
                IdentityProvider provider = service.GetIdentityProvider(authCredentials.ClientCredentials.UserName.UserName);
                if (provider != null &amp;&amp; provider.IdentityProviderType == IdentityProviderType.LiveId)
                {
                    authCredentials.SupportingCredentials = new AuthenticationCredentials();
                    authCredentials.SupportingCredentials.ClientCredentials =
                        Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice();
                }
            }

            break;
    }

    return authCredentials;
}

''' <summary>
''' Obtain the AuthenticationCredentials based on AuthenticationProviderType.
      ''' </summary>
      ''' <param name="service">A service management object.</param> 
      ''' <param name="endpointType">The authentication provider type used by the endpoint.</param>
''' <returns>Get filled credentials.</returns>
      Private Function GetCredentials(Of TService)(ByVal service As IServiceManagement(Of TService),
                                                   ByVal endpointType As AuthenticationProviderType) As AuthenticationCredentials
          Dim authCredentials As New AuthenticationCredentials()

          Select Case endpointType
              Case AuthenticationProviderType.ActiveDirectory
                  authCredentials.ClientCredentials.Windows.ClientCredential =
                      New System.Net.NetworkCredential(_userName, _password, _domain)

              Case AuthenticationProviderType.LiveId
                  authCredentials.ClientCredentials.UserName.UserName = _userName
                  authCredentials.ClientCredentials.UserName.Password = _password
                  authCredentials.SupportingCredentials = New AuthenticationCredentials()
                  authCredentials.SupportingCredentials.ClientCredentials =
                      Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice()

              Case Else ' For Federated and OnlineFederated environments.
                  authCredentials.ClientCredentials.UserName.UserName = _userName
                  authCredentials.ClientCredentials.UserName.Password = _password
                  ' For OnlineFederated single-sign on, you could just use current UserPrincipalName instead of
                  ' passing user name and password.
                  ' authCredentials.UserPrincipalName = UserPrincipal.Current.UserPrincipalName;  // Windows Kerberos

                  ' The service is configured for User Id authentication, but the user might provide Microsoft
                  ' account credentials. If so, the supporting credentials must contain the device credentials.
                  If endpointType.Equals(AuthenticationProviderType.OnlineFederation) Then
                      Dim provider As IdentityProvider =
                          service.GetIdentityProvider(authCredentials.ClientCredentials.UserName.UserName)

                      If provider IsNot Nothing AndAlso provider.IdentityProviderType = IdentityProviderType.LiveId Then
                          authCredentials.SupportingCredentials = New AuthenticationCredentials()
                          authCredentials.SupportingCredentials.ClientCredentials =
                              Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice()
                      End If
                  End If

          End Select

          Return authCredentials
      End Function

The AuthenticationCredentials object is configured according to the subscribed identity for the logged on user. Notice that user credentials for all types of identity providers are shown. The default case handles Microsoft Office 365/MOS managed domain, online users whose identities are federated in the cloud, and transitioned Microsoft account users. Now let’s take a look at what GetProxy actually does.


private TProxy GetProxy<TService, TProxy>(
    IServiceManagement<TService> serviceManagement,
    AuthenticationCredentials authCredentials)
    where TService : class
    where TProxy : ServiceProxy<TService>
{
    Type classType = typeof(TProxy);

    if (serviceManagement.AuthenticationType !=
        AuthenticationProviderType.ActiveDirectory)
    {
        AuthenticationCredentials tokenCredentials =
            serviceManagement.Authenticate(authCredentials);
        // Obtain discovery/organization service proxy for Federated, LiveId and OnlineFederated environments. 
        // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and SecurityTokenResponse.
        return (TProxy)classType
            .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse) })
            .Invoke(new object[] { serviceManagement, tokenCredentials.SecurityTokenResponse });
    }

    // Obtain discovery/organization service proxy for ActiveDirectory environment.
    // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and ClientCredentials.
    return (TProxy)classType
        .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(ClientCredentials) })
        .Invoke(new object[] { serviceManagement, authCredentials.ClientCredentials });
}

Private Function GetProxy(Of TService As Class,
                              TProxy As ServiceProxy(Of TService)) _
                          (ByVal serviceManagement As IServiceManagement(Of TService),
                           ByVal authCredentials As AuthenticationCredentials) As TProxy
    Dim classType As Type = GetType(TProxy)

    If serviceManagement.AuthenticationType <>
        AuthenticationProviderType.ActiveDirectory Then
        Dim tokenCredentials As AuthenticationCredentials =
            serviceManagement.Authenticate(authCredentials)
        ' Obtain discovery/organization service proxy for Federated, LiveId and OnlineFederated environments. 
        ' Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and SecurityTokenResponse.
        Return CType(classType _
        .GetConstructor(New Type() {GetType(IServiceManagement(Of TService)), GetType(SecurityTokenResponse)}) _
        .Invoke(New Object() {serviceManagement, tokenCredentials.SecurityTokenResponse}), TProxy)
    End If

    ' Obtain discovery/organization service proxy for ActiveDirectory environment.
    ' Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and ClientCredentials.
    Return CType(classType _
        .GetConstructor(New Type() {GetType(IServiceManagement(Of TService)), GetType(ClientCredentials)}) _
        .Invoke(New Object() {serviceManagement, authCredentials.ClientCredentials}), TProxy)
End Function

For all deployments other than on-premises (Active Directory, without claims), the Authenticate method is invoked and then the service proxy is instantiated. Notice that the authentication credentials returned from Authenticate contain the security token response that is used in the service proxy constructor. The generic GetProxy method shown previously can be used to obtain an object reference to either OrganizationServiceProxy or DiscoveryServiceProxy.

See Also

Connect with Microsoft Office 365 and Microsoft Dynamics CRM Online
Synchronized users in Microsoft Dynamics CRM Online and Office 365
Sample: Authenticate users with Microsoft Dynamics CRM 2013 web services
Helper code: ServerConnection class
Active Directory and claims-based authentication
Simplified connection to Microsoft Dynamics CRM 2013