Auth node reference

Microsoft Intune node

Lets you integrate with Microsoft Intune using Microsoft Graph APIs. Microsoft Intune lets you control features and settings on Android, Android Enterprise, iOS/iPadOS, macOS, and Windows 10/11 devices in your organization.

The Microsoft Intune node checks the device details and determines the device’s compliance status. You can enable this node to save device information to shared state for subsequent use by other nodes in the journey.

For more information about Microsoft Intune, refer to the Microsoft Intune documentation.

Availability

Product Available?

PingOne Advanced Identity Cloud

Yes

PingAM (self-managed)

Yes

Ping Identity Platform (self-managed)

Yes

Inputs

This node needs DeviceID to be in either the shared state or in the request header.

Dependencies

You must set up Microsoft Intune before using this node in your PingOne Advanced Identity Cloud environment. Follow the Get started with your Microsoft Intune deployment document to set up and use a production version of Microsoft Intune.

Microsoft Intune requires a Microsoft Graph API application to be registered. Follow the register apps to use the Microsoft Graph API steps to complete the registration process.

Set the following Microsoft Intune and Graph API permissions:

API / Permission Type Description

Microsoft Intune

get_data_warehouse

Delegated

Get data warehouse information from Microsoft Intune

get_device_compliance

Application

Get device state and compliance information from Microsoft Intune

pfx_cert_provider

Application

PFX certificate management

scep_challenge_provider

Application

SCEP challenge validation

send_data_usage

Application

Exchange device telecom and Wi-Fi data usage information with Microsoft Intune

update_device_attributes

Application

Send device attributes to Microsoft Intune

update_device_health

Application

Send device threat information to Microsoft Intune

Microsoft Graph API

DeviceManagementManagedDevices.Read.All

Delegated

Read Microsoft Intune devices

User.Read

Delegated

Sign in and read user profile

Verifying Intune setup

Use the following cURL commands to verify your Intune setup before using the node:

  1. This first command retrieves the access token needed by the Intune node.

    1. Sample cURL request:

      curl \
       --location 'https://login.microsoftonline.com/tenant ID/oauth2/v2.0/token' \
       --header 'Content-Type: application/x-www-form-urlencoded' \
       --data-urlencode 'client_id=application client ID' \
       --data-urlencode 'client_secret=client secret' \
       --data-urlencode 'scope=https://graph.microsoft.com/.default' \
       --data-urlencode 'grant_type=password' \
       --data-urlencode 'username=Azure admin username' \
       --data-urlencode 'password=Azure admin pwd'
    2. Sample response:

      {
          "token_type": "Bearer",
          "scope": "profile openid email https://graph.microsoft.com/DeviceManagementManagedDevices.Read.All https://graph.microsoft.com/User.Read https://graph.microsoft.com/.default",
          "expires_in": 3971,
          "ext_expires_in": 3971,
          "access_token": "This will be the jwt token used to retrieve the device info cURL"
      }
  2. This second command retrieves the device info:

    1. Sample cURL request:

      curl \
       --location 'https://graph.microsoft.com/v1.0/deviceManagement/manageddevices/Intune device ID' \
       --header 'Authorization: Bearer This is the jwt token returned by the cURL command above'
    2. Sample response:

      {
          "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#deviceManagement/managedDevices/$entity",
          "id": "f61dc341-c9c9-40c1-abbd-6997016f4c9e",
          "userId": "0f7e78ba-6e1f-485b-8b8b-fb86895f0498",
          "deviceName": "WINDEV2404EVAL",
          "managedDeviceOwnerType": "company",
          "enrolledDateTime": "2024-05-15T14:13:19.376941Z",
          "lastSyncDateTime": "2024-05-16T03:45:42.4309247Z",
          "operatingSystem": "Windows",
          "complianceState": "compliant",
          "jailBroken": "Unknown",
          "managementAgent": "mdm",
          "osVersion": "10.0.22621.3447",
          "easActivated": true,
          "easDeviceId": "24783A3196BAFE89291A012E4B607591",
          "easActivationDateTime": "2024-05-15T14:25:40.632661Z",
          "azureADRegistered": true,
          "deviceEnrollmentType": "windowsAzureADJoin",
          "activationLockBypassCode": null,
          "emailAddress": "",
          "azureADDeviceId": "e7f59723-3b4c-4783-89bf-9e42d492f4ac",
          "deviceRegistrationState": "registered",
          "deviceCategoryDisplayName": "",
          "isSupervised": false,
          "exchangeLastSuccessfulSyncDateTime": "0001-01-01T00:00:00Z",
          "exchangeAccessState": "none",
          "exchangeAccessStateReason": "none",
          "remoteAssistanceSessionUrl": "",
          "remoteAssistanceSessionErrorDetails": "",
          "isEncrypted": false,
          "userPrincipalName": "",
          "model": "VirtualBox",
          "manufacturer": "innotek GmbH",
          "imei": null,
          "complianceGracePeriodExpirationDateTime": "9999-12-31T23:59:59.9999999Z",
          "serialNumber": "0",
          "phoneNumber": null,
          "androidSecurityPatchLevel": null,
          "userDisplayName": "acarter",
          "configurationManagerClientEnabledFeatures": null,
          "wiFiMacAddress": null,
          "deviceHealthAttestationState": null,
          "subscriberCarrier": "",
          "meid": null,
          "totalStorageSpaceInBytes": 133661982720,
          "freeStorageSpaceInBytes": 74671194112,
          "managedDeviceName": "acarter_Windows_5/15/2024_2:13 PM",
          "partnerReportedThreatState": "unknown",
          "requireUserEnrollmentApproval": null,
          "managementCertificateExpirationDate": "2025-05-15T03:56:04Z",
          "iccid": "",
          "udid": "",
          "notes": null,
          "ethernetMacAddress": "08002732B5A2",
          "physicalMemoryInBytes": 0,
          "enrollmentProfileName": "",
          "deviceActionResults": []
      }

Ensure you are using the correct device ID when performing the verification tests. You can retrieve the Intune device ID from the Hardware section:

intune deviceid

Configuration

The configurable properties for this node are:

Property Usage

DeviceID Attribute Name

Name of the header or shared state variable for storing the deviceID value. The value is the SSL_Client_S_DN in the client certificate presented at the TLS termination gateway. The format should be: CN=f47d8e59-b60e-48a5-adc1-622cb2244zzz.

DeviceID in SharedState

Boolean.

  • If enabled, the node takes the device ID from shared state.

  • If disabled, the node takes the device ID from the request header.

Default: disabled.

The DeviceID in SharedState toggle is used to determine where to look for the device ID value. If the DeviceID in SharedState toggle is enabled, the device ID is available in the shared state, and if it’s disabled, the device ID is in the header.

Tenant ID

Tenant’s global unique identifier (GUID) in Azure Active Directory (AD).

Application (client) ID

The application ID or client ID is a value the Microsoft identity platform assigns to your application when you register it in Azure AD.

Client Secret

Sometimes called an application password, a client secret is a string value your application can use in place of a certificate to identify itself.

Azure Admin User Name

The administrative username in Azure.

Azure Admin User Password

The administrative password in Azure.

Save Device Properties to SharedState

If enabled, the device information is saved to the shared state with INTUNE_ prepended to the key name. Null and empty string values are not placed into shared state.

Refer to the Properties table in Microsoft Intune documentation for the managed device properties.

Save installed apps to SharedState

If enabled, the apps installed on the Mobile Device are extracted and saved to the Shared State with the key name - INTUNE_INSTALLED_APPS.

Outputs

  • If Save Device Properties to SharedState is enabled, the device property available in Microsoft Intune service is stored on the shared state.

  • If Save installed apps to ShatedState is enabled, the details of application installed on the device are stored on the shared state.

Outcomes

Compliant

The device is compliant.

Not Compliant

The device does not comply with the policy.

In Grace Period

The device is not-compliant, but it’s in the grace period defined by the administrator.

Config Manager

The device is managed by Microsoft Intune’s Configuration Manager.

Conflict

Multiple settings are applied to the same device and Intune can’t sort out the conflict. An administrator should review.

No Id

No device ID is found in the header or shared state.

Status Unknown

The device is offline or failed to communicate with Intune or Azure AD.

Error

An error occurred within the node. Related stacktrace and message are placed in the shared state.

Learn more in the Microsoft Graph API documentation on Compliance State.

Errors

Review the log messages to find the reason for the error and address the issue appropriately.

Examples

The following example uses PingGateway to get the device ID from the device’s certificate for mutual TLS (mTLS).

PingGateway completes the TLS handshake before the request accesses the journey, requesting mTLS.

PingGateway extracts the device ID from the device certificate used for mTLS. PingGateway passes the device ID in a header to this node, the first node of the example journey.

  1. When setting up Microsoft Intune, modify the user certificate SCEP profile to include the device ID.

    In this example, the certificate holds the device ID as the subdomain of the Subject Alternative Name DNS name field.

  2. Enroll devices managed with Microsoft Intune to get the new user certificate containing the device ID.

    This can require rebooting or syncing the device.

  3. Create the journey:

    microsoft intune journey
    • The Microsoft Intune node verifies client device compliance.

    • For compliant devices, an Inner Tree Evaluator node invokes a two-factor journey (not shown) to authenticate the user.

      On success, a Modify Auth Level node sets an authentication level of 3.

    • Otherwise, a Scripted Decision node determines whether to continue the journey. If so, the two-factor journey authenticates the user.

      On success in this case, the Modify Auth Level node sets an authentication level of 2.

  4. Configure PingGateway and Microsoft Intune for mTLS between devices managed with Microsoft Intune.

    Make sure the PingGateway trust manager trusts the SCEP CA cert.

    Let PingGateway use "clientAuth": "REQUEST" for mTLS so connections don’t immediately fail if they’re missing a certificate.

    To avoid a popup where the user has to select a certificate, create a Microsoft Intune policy to automatically link the user certificate to the PingGateway URL.

  5. Configure a route for PingGateway to extract the device ID from the certificate, add it in a header to the request, and forward the request to the journey.

    In this example, the route uses a script, ExtractDeviceIdFromClientCert.groovy, to extract the device ID from the certificate:

    import java.security.cert.X509Certificate
    
    // Get the device ID from the client certificate and put it in the "SSL_Client_S_DN" request header.
    
    def clientCert = contexts.client.certificates[0]
    if (!(clientCert instanceof X509Certificate)) {
        // No client certifcate provided
        next.handle(context, request)
    }
    
    // Extract the device ID from the client certificate's Subject Alternative Name (SAN) DNS entry.
    // In this example, the device ID is the first part of the DNS name before the first dot,
    // ("device123.example.com" -> "device123").
    // Adapt this logic to extract the device ID based on the client certificate's structure.
    def subjectAltNames = clientCert.getSubjectAlternativeNames()
    subjectAltNames.each { san ->
        switch((Integer)san.get(0)) {
            case 2: // DNS Name
                Object data = san.get(1);
                if (data instanceof String) {
                    def dns = (String) data
                    def deviceId = dns.substring(0, dns.indexOf("."))
                    request.headers.add("SSL_Client_S_DN", "CN=" + deviceId)
                    break
                }
                break
            default:
                break
        }
    }
    
    next.handle(context, request)

    The route, mtls-intune.json, adds the device ID to the request header and directs the request to the journey:

    {
      "name": "mtls-intune",
      "condition": "${find(request.uri.path, '/mtls-intune')}",
      "properties": {
        "tenantUrl": "https://openam-docs-rapid.forgeblocks.com/"
      },
      "baseURI": "&{tenantUrl}/am/XUI/?realm=alpha&authIndexType=service&authIndexValue=intune",
      "heap": [
        {
          "name": "StaticResponseHandlerForDebugging",
          "type": "StaticResponseHandler",
          "config": {
            "status": 200,
            "headers": {
              "Content-Type": [
                "text/plain; charset=UTF-8"
              ]
            },
            "entity": "mTLS\n cert: ${contexts.client.certificates[0]}"
          }
        },
        {
          "name": "ExtractDeviceIdFromClientCert",
          "type": "ScriptableFilter",
          "config": {
            "type": "application/x-groovy",
            "file": "ExtractDeviceIdFromClientCert.groovy"
          },
          "_capture": "filtered_request"
        },
        {
          "name": "PathRewriteFilter",
          "type": "UriPathRewriteFilter",
          "config": {
            "mappings": {
              "/mtls-intune": "/am/XUI"
            }
          }
        }
      ],
      "handler": {
        "type": "Chain",
        "config": {
          "filters": [
            "ExtractDeviceIdFromClientCert",
            "PathRewriteFilter"
          ],
          "_handler": "StaticResponseHandlerForDebugging",
          "handler": "ReverseProxyHandler"
        }
      }
    }

    Add the script to the scripts/groovy directory and the route to the config/routes directory of your PingGateway configuration.

  6. Make sure the device goes through the route on the way to the journey.

    For example, consider a journey called intune in the alpha realm with URL https://myTenant.forgeblocks.com/am/XUI/?realm=alpha&authIndexType=service&authIndexValue=intune. PingGateway listens at https://gateway.example.com:8443 and the path to access the route is /mtls-intune. The device accesses the journey through PingGateway at https://gateway.example.com:8443/mtls-intune/?realm=alpha&authIndexType=service&authIndexValue=intune.

Learn more in the following documentation: