Skip to content

Commit

Permalink
Add SAML Provider for Azure AD
Browse files Browse the repository at this point in the history
  • Loading branch information
greenpau committed Feb 25, 2020
1 parent 62c8ec8 commit 41b7183
Show file tree
Hide file tree
Showing 25 changed files with 648 additions and 12 deletions.
214 changes: 214 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ It can be used as:
![](.screenshot.png)

## Supported Provider Backends

The following providers (login backends) are supported.

* [Htpasswd](#htpasswd)
Expand All @@ -44,6 +45,8 @@ The following providers (login backends) are supported.
* Bitbucket login
* Facebook login
* Gitlab login
* [SAML](#saml)
* Azure AD login

## Questions

Expand Down Expand Up @@ -333,6 +336,217 @@ if loginsrv is routed through a reverse proxy, if the headers `X-Forwarded-Host`
$ docker run -p 80:80 tarent/loginsrv -github client_id=xxx,client_secret=yyy
```

## SAML

### Azure AD Applications

#### Caddy Configuration

The SAML provider supports the following parameters:

| **Parameter-Name** | **Description** |
| --- | --- |
| `azure_enabled` | Enable Azure AD |
| `azure_idp_metadata_location` | The url or path to Azure IdP Metadata |
| `azure_idp_sign_cert_location` | The path to Azure IdP Signing Certificate |
| `azure_tenant_id` | Azure Tenant ID |
| `azure_application_id` | Azure Application ID |
| `azure_application_name` | Azure Application Name |

The following is the configuration for Caddy `login` plugin:

```
login {
success_url /private
azure_enabled true
azure_idp_metadata_location /etc/saml/azure_ad_idp_metadata.xml
azure_idp_sign_cert_location /etc/saml/azure_ad_signing_cert.pem
azure_tenant_id 1b9e886b-8ff2-4378-b6c8-6771259a5f51
azure_application_id 623cae7c-e6b2-43c5-853c-2059c9b2cb58
azure_application_name "My Infosec"
azure_metadata_url "https://localhost:8080/login"
azure_acs_url "https://localhost:8080/login"
# for testing, where no https is available, don't set the secure flag for the.
cookie_secure false
}
```

#### Set Up Azure AD Application

In Azure AD, you will have an application, e.g. "My Infosec".

The application is a Caddy web server running on port 8080 on
`localhost`. This example meant to emphasize that the authorization
is asynchronious. That is when a user clicks on "My Infosec" icon
in Office 365, the browser takes the user to the login page
at URL `https://localhost:8080/login`.

![Azure AD App Registration - Overview](./docs/_static/images/azure_app_registration_overview.png)

The Application Identifiers are as follows:

* Application (client) ID: `623cae7c-e6b2-43c5-853c-2059c9b2cb58`
* Directory (tenant) ID: `1b9e886b-8ff2-4378-b6c8-6771259a5f51`
* Object ID: `515d2e8b-7548-413f-abee-a23ece1ea576`

The "Branding" page configures "Home Page URL".

![Azure AD App Registration - Branding](./docs/_static/images/azure_app_registration_branding.png)

For demostration purposes, we will create the following "Roles" in the application:

* Viewer
* Editor
* Administrator

Use "Manifest" tab to add roles in the manifest via `appRoles` key:

![Azure AD App Registration - Manifest - User Roles](./docs/_static/images/azure_app_registration_user_roles.png)

```json
{
"allowedMemberTypes": [
"User"
],
"description": "Administrator",
"displayName": "Administrator",
"id": "91287df2-7028-4d5f-b5ae-5d489ba217dd",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "AzureAD_Administrator"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Editor",
"displayName": "Editor",
"id": "d482d827-1757-4f60-9bea-021c10037674",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "AzureAD_Editor"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Viewer",
"displayName": "Viewer",
"id": "c69f7abd-0a88-401e-b515-92d74b6fff2f",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "AzureAD_Viewer"
}
```

After, we added the roles, we could assign any of the roles to a user:

![Azure AD App - Users and Groups - Add User](./docs/_static/images/azure_app_add_user.png)

The app is now available to the provisioned users in Office 365:

![Office 365 - Access Application](./docs/_static/images/azure_app_user_access.png)

#### Configure SAML Authentication

Go to "Enterprise Application" and browse to "My Infosec" application.

There, click "Single Sign-On" and select "SAML" as the authentication method.

![Azure AD App - Enable SAML](./docs/_static/images/azure_app_saml_enable.png)

Next, in the "Set up Single Sign-On with SAML", provide the following
"Basic SAML Configuration":

* Identifier (Entity ID): `https://localhost:8080/login`
* Reply URL (Assertion Consumer Service URL): `https://localhost:8080/login`

![Azure AD App - Basic SAML Configuration](./docs/_static/images/azure_app_saml_id.png)

Under "User Attributes & Claims", add the following claims to the list of
default claims:

| **Namespace** | **Claim name** | **Value** |
| --- | --- | --- |
| `http://claims.contoso.com/SAML/Attributes` | `RoleSessionName` | `user.userprincipalname` |
| `http://claims.contoso.com/SAML/Attributes` | `Role` | `user.assignedroles` |
| `http://claims.contoso.com/SAML/Attributes` | `MaxSessionDuration` | `3600` |

![Azure AD App - User Attributes and Claims](./docs/_static/images/azure_app_saml_claims.png)

Next, record the following:
* App Federation Metadata Url
* Login URL

Further, download:
* Federation Metadata XML
* Certificate (Base64 and Raw)

![Azure AD App - SAML Signing Certificate](./docs/_static/images/azure_app_saml_other.png)


#### Azure AD IdP Metadata and Certificate

The following command downloads IdP metadata file for Azure AD Tenant with
ID `1b9e886b-8ff2-4378-b6c8-6771259a5f51`. Please note the `xmllint` utility
is a part of `libxml2` library.

```bash
curl -s -L -o /tmp/federationmetadata.xml https://login.microsoftonline.com/1b9e886b-8ff2-4378-b6c8-6771259a5f51/federationmetadata/2007-06/federationmetadata.xml
sudo mkdir -p /etc/saml
cat /tmp/federationmetadata.xml | xmllint --format - | sudo tee /etc/saml/azure_ad_idp_metadata.xml
```

The `/etc/saml/azure_ad_idp_metadata.xml` contains IdP metadata. This file contains
the data necessary to verify the SAML claims received by this service and signed
by Azure AD. The `idp_metadata` argument is being used to pass the location of
IdP metadata.

Next, download the "Certificate (Base64)" and store it in `/etc/saml/azure_ad_signing_cert.pem`.

#### User Interface Options

First option is a login button on the login server web page. Once Azure AD has
been enabled, the `/login` page will have "Sign in with Office 365" button

![Azure AD App - Login with Azure Button](./docs/_static/images/login_with_azure_button.png?width=20px)

Second option is Office 365 applications. When a user click on the
application's icon in Office 365, the user gets redirected to the web
server by Office 365.

![Office 365 - Access Application](./docs/_static/images/azure_app_user_access.png)

The URL is `https://localhost:8080/login`.

The below is the headers of the `POST` request that the user's browser makes:

```
Method: POST
URL: /login
Protocol: HTTP/2.0
Host: localhost:8080
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,ru;q=0.8
Cache-Control: max-age=0
Content-Length: 7561
Content-Type: application/x-www-form-urlencoded
Origin: https://login.microsoftonline.com
Referer: https://login.microsoftonline.com/
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Upgrade-Insecure-Requests: 1
```

The above redirect contains `login.microsoftonline.com` in the request's
`Referer` header. It is the trigger to perform SAML-based authorization.

## Templating

A custom template can be supplied by the parameter `template`.
Expand Down
6 changes: 3 additions & 3 deletions caddy/demo/Caddyfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

http://localhost:8080 {

log stdout
log stdout
root {$PWD}/webroot
ext .html
header /private Cache-Control "no-cache, no-store, must-revalidate"

jwt {
path /private
redirect /login
Expand All @@ -20,5 +20,5 @@ http://localhost:8080 {
# for testing, where no https is available, don't set the secure flag for the.
cookie_secure false
}

}
32 changes: 32 additions & 0 deletions caddy/demo/conf/saml/Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
*:8080 {
tls /etc/saml/server.crt /etc/saml/server.key
log stdout
root {$PWD}/webroot
ext .html
header /private Cache-Control "no-cache, no-store, must-revalidate"

jwt {
path /private
redirect /login
allow role AzureAD_Viewer
allow role AzureAD_Editor
allow role AzureAD_Administrator
}

login {
success_url /private

azure_enabled true
azure_idp_metadata_location /etc/saml/azure_ad_idp_metadata.xml
azure_idp_sign_cert_location /etc/saml/azure_ad_signing_cert.pem
azure_tenant_id 1b9e886b-8ff2-4378-b6c8-6771259a5f51
azure_application_id 623cae7c-e6b2-43c5-853c-2059c9b2cb58
azure_application_name "My Infosec"
azure_metadata_url "https://localhost:8080/login"
azure_acs_url "https://localhost:8080/login"

# for testing, where no https is available, don't set the secure flag for the.
cookie_secure false
}

}
Loading

0 comments on commit 41b7183

Please sign in to comment.