# OpenID Connect with Azure Blob Storage

OpenID Connect is an authentication protocol built on OAuth 2.0 that allows an application to request access on behalf of an end user.

As this document is intended to provide only a basic overview, refer to the official documentation for further information, for example:
<https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols>.

In short, OpenID Connect is a protocol for providing SSO, single sign-on, by using the native browser through a common identity provider, the **Authorization Server**. It is built on top of OAuth 2.0 and allows an application to request access to a system on behalf of an end user. The **Client** is the application requesting access to the secured **Resource Server** on behalf of the end user, the **Resource Owner**. Any **Authorization Server** that supports OpenID Connect can, of course, be used in combination with UniversalPlantViewer. The **Resource Server** must support plain file access in a folder hierarchy, as opposed to an API such as Google Drive.

Supporting specific Resource Server APIs requires additional development effort on the CAXperts side and must be agreed separately.

This example uses Azure AD in combination with Azure Blob Storage.

The OpenID Connect protocol is supported in UniversalPlantViewer **version 05.02** and later.

## High-level schema for Azure AD

<img src=".\media/OpenIDConnect_image2.png" width="652" height="441">

Conceptually, UniversalPlantViewer does not handle any user secret. The **Authorization Server** handles the sign-in independently and issues a token that can be used by UniversalPlantViewer to access the protected resource.

Therefore, it is not possible for the **Client**, UniversalPlantViewer, to leak a user password. Only the token could become a target for attacks and, if stolen, could be used to access the **Resource Server** for a limited period.

Refer to the **Authorization Server** documentation for further security measures, for example Multi-Factor Authentication or specific authorisation rules.

## Configuration in UniversalPlantViewer

UniversalPlantViewer uses the `IdentityModel.OidcClient` library internally, currently version `2.9.0.0`. Refer to the library options for further details.

The following extensions to the library's options are available:

-   **FrontChannelExtraParameters**: set additional request-query parameters for the authentication request, for example the resource parameter

-   **BackChannelExtraParameters**

-   **AuthorizationHeaders**: set static header values that should be sent when authenticated

-   **EnableLog**: when enabled, includes the `OidcClient2` log in the application

The configuration-file example for Azure is shown below. Missing configuration options use the library default values.

The **EnableLog** property should be enabled while setting up the configuration. Authentication problems are then logged to the general UniversalPlantViewer log.

After configuration has been completed, it is advisable to disable this setting so that security-relevant information is not written permanently to the log file.

## authenticationConfig.json

{\
\"Oidc\":{\
\"FrontChannelExtraParameters\":{\
\"resource\":\"<https://upv.blob.core.windows.net>\"\
},\
\"AuthorizationHeaders\":{\
\"x-ms-version\":\"2017-11-09\"\
},\
\"EnableLog\":true,\
\"Authority\":\"https://sts.windows.net/e1765baf-2fe4-4b9e-87ee-d130dde50afa\",\
\"ClientId\":\"5c2f88a0-766f-464d-bdad-d40ec1d4fb33\",\
\"Scope\":\"openid profile offline_access
https://storage.azure.com/user_impersonation\",\
\"RedirectUri\":\"upvapi://auth\",\
\"RefreshDiscoveryDocumentForLogin\":true,\
\"RefreshDiscoveryOnSignatureFailure\":false,\
\"ResponseMode\":1,\
\"LoadProfile\":false,\
\"Flow\":0,\
\"TokenClientAuthenticationStyle\":1,\
\"Policy\":{\
\"Discovery\":{\
\"ValidateEndpoints\":false\
},\
\"RequireAccessTokenHash\":false,\
\"RequireIdentityTokenOnRefreshTokenResponse\":false,\
},\
}\
}

The following options must be adjusted to your environment:

-   **Resource**: the name of the blob storage

-   **Authority**: the Microsoft authorisation endpoint for your organisation, using for example the Directory, tenant, ID shown below. Refer to the Microsoft documentation for further options.

-   **ClientId**: the identifier for the application registration, that is, the Application, client, ID shown below

Azure-specific settings:

-   **ValidateEndpoints**: set this to `false` when the endpoint is on a different host from the authority

-   **AuthorizationHeader**: `x-ms-version`, determines the Azure API version

-   **RequireAccessTokenHash**: `false`

-   **LoadProfile**: `false`, not required by UniversalPlantViewer and requires additional permission

The required configuration IDs can be found in the app registrations overview:

![](.\media/OpenIDConnect_image3.png)

The configuration file is recognised automatically in the `Data` folder of the UniversalPlantViewer model at `Data\authenticationConfig.json`. It must be accessible without authentication, anonymous access.

It is not possible to set individual files to anonymous access in Azure Blob Storage.

As a workaround, the file can be stored in any other location, for example in a separate blob-storage container with global anonymous access. The file name does not matter in this context.

The user must open the model once by using a `upvapi://` link such as the one below. The configuration is then stored on the user device and recognised automatically for later attempts in the specified domain.

upvapi://https://upv.blob.core.windows.net/\$web/demoplantModel/?CMD!SetAuthConfig=https%3A%2F%2Fupv.blob.core.windows.net%2F%24web%2FdemoplantModel%2F!https%3A%2F%2Fupv.blob.core.windows.net%2FauthenticationConfig.json

1)  <https://upv.blob.core.windows.net/$web/demoplantModel/>  
    → model location for opening directly through the link

2)  `SetAuthConfig` parameter 1  
    `https%3A%2F%2Fupv.blob.core.windows.net%2F%24web%2FdemoplantModel%2F`  
    → domain for which the configuration is relevant, subroutes use the provided configuration when no other configuration is specified

3)  `SetAuthConfig` parameter 2  
    `https%3A%2F%2Fupv.blob.core.windows.net%2FauthenticationConfig.json`  
    → path to the configuration file, which must be accessible without authentication, supports file, web, or URI paths

The parameters of `SetAuthConfig` must be URL-encoded.

## Configuration in Azure

## Azure Blob storage

For a general overview see
<https://docs.microsoft.com/en-us/azure/storage/blobs/>

### Set up a storage account

<https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal>

### Set up the containers

<https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal>

You need one container for the configuration file. Set the access level to anonymous.

Upload the UniversalPlantViewer configuration file there.

You need another container for the secured UniversalPlantViewer model data. Set the access level to private.

Uploading multiple files or folders can be done by using Azure Storage Explorer.

<https://docs.microsoft.com/en-us/azure/vs-azure-tools-storage-explorer-blobs>

### Add user permissions

<https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad-rbac-portal>

For the container you will have to set up user and group permissions.

To allow delegated access to the storage account, assign the **Storage Blob Data Reader** role for read-only access.

Depending on your requirements, other roles in the **Storage Blob Data** group can also be used.

![](.\media/OpenIDConnect_image4.png)

## App registration in Azure Active Directory

<https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app>

Set **Redirect URI** to `upvapi://auth`.

The Redirect URI must match the one provided in the configuration file.

A client secret is not required because UniversalPlantViewer is a public client.

### Add required permission

![](.\media/OpenIDConnect_image5.png)
UniversalPlantViewer needs to access the storage on behalf of the user. Therefore, add the following permission to the registration: **Azure Storage -- user_impersonation**.

Optionally, admin consent can be granted so that end users no longer need to provide consent individually.

### Add relay page (optional)

In Chrome, some calls to `upvapi://` were observed to be ignored silently when the browser does not have focus, which can happen, for example, when the user is already signed in.

Chrome treats this as a security feature.

In addition, there is no indicator in the browser when the sign-in has completed, and the browser window may be closed too early.

As a workaround, a relay web page can be used as an additional Redirect URI, see the attached example page.

![](.\media/OpenIDConnect_image6.png)

The Redirect URI in the UniversalPlantViewer configuration file must be adjusted accordingly.

## loginRedirect.html (example code)
```html
<html>
    <head>
        <title>UniversalPlantViewer Login</title>
    </head> 
    <body>
        <p>
            UniversalPlantViewer login should be succeeded <br>
            You can close this window now. If there is a problem, you can reissue the login request with below link.
        </p>
        <a id="#authLink">Login</a>
    </body>
    <script>
        var url = 'upvapi://auth' + window.location.search;
        function login() {
            window.location.assign(url);
        }
        window.onload = function() {
            var link = document.getElementById('#authLink');
            link.href = url;
            login();
        }
    </script>
</html>
```

### Case sensitivity of urls

URLs in Azure Blob Storage are, unlike many other systems, case-sensitive. Therefore, the file name capitalisation in the UPV model must remain unchanged.

The following capitalisation must also be considered for additional configuration files:

-   defaultConfig.upv
-   authenticationConfig.json
-   volumes.xls/xlsx
-   attributes.xls/xlsx
-   intelliPidAttributes.xls/xlsx
-   attributeData.xlsx
-   intelliPidAttributeData.xlsx
-   links.xls/xlsx/txt
-   intelliPidLinks.xls/xlsx/txt
-   defaultPackages.json/xlsx
-   upvcolorindex.txt
-   ReportDefinition.xls/xlsx
-   intelliPidReportDefinition.xls/xlsx
-   upvobjectsindex.txt
-   upvsketchitemindex.txt
-   upvintellipidsketchitemindex.txt
-   Measurements.xlsx
-   Endpreps.xlsx
-   projectMessage.png/jpg/jpeg
