saml

package module
v0.0.0-...-8963980 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 19, 2020 License: Apache-2.0 Imports: 21 Imported by: 0

README

caddy-auth-saml

SAML Authentication Plugin for Caddy v2.

The plugin supports the following identity providers:

Getting Started

This plugin is an application in itself. It has a simple UI and a routine that checks the validity of the SAML assertions provided by an Identity Provider (IdP).

Time Synchronization

Importantly, SAML assertion validation checks timestamps. It is critical that the application validating the assertions maintains accurate clock. The out of sync time WILL result in failed authentications.

Authentication Endpoint

Each instance of the plugin requires an endpoint. Let's examine the endpoint /saml provided in a sample configuration file:

cat assets/conf/Caddyfile.json | jq '.apps.http.servers.srv0.routes'

The output is:

{
  "handle": [
    {
      "handler": "authentication",
      "providers": {
        "saml": {
          "auth_url_path": "/saml",
          "jwt": {
            "token_name": "JWT_TOKEN",
            "token_secret": "383aca9a-1c39-4d7a-b4d8-67ba4718dd3f",
            "token_issuer": "7a50e023-2c6e-4a5e-913e-23ecd0e2b940"
          },
          "azure": {
            "idp_metadata_location": "/etc/caddy/auth/saml/idp/azure_ad_app_metadata.xml",
            "idp_sign_cert_location": "/etc/caddy/auth/saml/idp/azure_ad_app_signing_cert.pem",
            "tenant_id": "1b9e886b-8ff2-4378-b6c8-6771259a5f51",
            "application_id": "623cae7c-e6b2-43c5-853c-2059c9b2cb58",
            "application_name": "My Gatekeeper",
            "entity_id": "urn:caddy:mygatekeeper",
            "acs_urls": [
              "https://mygatekeeper/saml",
              "https://mygatekeeper.local/saml",
              "https://192.168.10.10:3443/saml",
              "https://localhost:3443/saml"
            ]
          },
          "ui": {
            "template_location": "assets/ui/ui.template",
            "allow_role_selection": false
          }
        }
      }
    }
  ],
  "match": [
    {
      "path": [
        "/saml*"
      ]
    }
  ],
  "terminal": true
}
User Interface (UI)

The SAML endpoint /saml serves a UI. This is defined by the following snippet of the above configuration. The /saml* ensures that anything matching /saml would end at the above handler.

  "match": [
    {
      "path": [
        "/saml*"
      ]
    }
  ],

The UI template is Golang template. The template in assets/ui/ui.template is the default UI served by the plugin.

  • template_location: The location of a custom UI template
  • allow_role_selection: Enables or disables the ability to select a role after successful validation of a SAML assertion.
          "ui": {
            "template_location": "assets/ui/ui.template",
            "allow_role_selection": false
          }
JWT Token

After a successful validation of a SAML assertion, the plugin issues a JWT token.

  • token_name: The name of the issues token (default: 'jwt_token`)
  • token_secret: The token signing secret (symmetric, i.e. HMAC algo)
  • token_key: (TODO: not supported) The token signing public/private key pair (asymmetric, i.e. RSA or ECDSA algo).
  • token_issuer: The value of iss field inserted by the plugin.
          "jwt": {
            "token_name": "JWT_TOKEN",
            "token_secret": "383aca9a-1c39-4d7a-b4d8-67ba4718dd3f",
            "token_issuer": "7a50e023-2c6e-4a5e-913e-23ecd0e2b940"
          },

The issued token will be passed to a requester via:

  • The cookie specified in token_name key
  • The Authorization header via Bearer directive

Azure Active Directory (Office 365) Applications

Plugin Configuration

First, fetch the Azure IdP plugin configuration:

cat assets/conf/Caddyfile.json | jq '.apps.http.servers.srv0.routes[0].handle[0].providers.saml.azure'

The Azure configuration:

{
  "idp_metadata_location": "assets/idp/azure_ad_app_metadata.xml",
  "idp_sign_cert_location": "assets/idp/azure_ad_app_signing_cert.pem",
  "tenant_id": "1b9e886b-8ff2-4378-b6c8-6771259a5f51",
  "application_id": "623cae7c-e6b2-43c5-853c-2059c9b2cb58",
  "application_name": "My Gatekeeper",
  "entity_id": "urn:caddy:mygatekeeper",
  "acs_urls": [
    "https://mygatekeeper/saml",
    "https://mygatekeeper.local/saml",
    "https://192.168.10.10:3443/saml",
    "https://localhost:3443/saml"
  ]
}

The plugin supports the following parameters for Azure Active Directory (Office 365) applications:

Parameter Name Description
idp_metadata_location The url or path to Azure IdP Metadata
idp_sign_cert_location The path to Azure IdP Signing Certificate
tenant_id Azure Tenant ID
application_id Azure Application ID
application_name Azure Application Name
entity_id Azure Application Identifier (Entity ID)
acs_urls One of more Assertion Consumer Service URLs

The acs_urls must list all URLs the users of the application can reach it at.

Set Up Azure AD Application

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

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

Azure AD App Registration - Overview

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

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

Azure Role Name Role Name in SAML Assertion
Viewer AzureAD_Viewer
Editor AzureAD_Editor
Administrator AzureAD_Administrator

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

Azure AD App Registration - Manifest - User Roles

{
  "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

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

Office 365 - Access Application

Configure SAML Authentication

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

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

Azure AD App - Enable SAML

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

  • Identifier (Entity ID): urn:caddy:mygatekeeper
  • Reply URL (Assertion Consumer Service URL): https://localhost:3443/saml

Azure AD App - Basic SAML Configuration

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

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

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.


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/caddy/auth/saml/idp/
cat /tmp/federationmetadata.xml | xmllint --format - | sudo tee /etc/caddy/auth/saml/idp/azure_ad_app_metadata.xml

The /etc/caddy/auth/saml/idp/azure_ad_app_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/caddy/auth/saml/idp/azure_ad_app_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 /saml page will have "Sign in with Office 365" button

Azure AD App - Login with Azure Button

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

The URL is https://localhost:3443/saml.

Development Notes

The below are the headers of the redirected POST request that the user's browser makes upon clicking "My Gatekeeper" application:

Method: POST
URL: /saml
Protocol: HTTP/2.0
Host: localhost:3443
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.

AWS Cognito

TODO.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AuthProvider

type AuthProvider struct {
	Name string `json:"-"`
	CommonParameters
	Azure *AzureIdp      `json:"azure,omitempty"`
	UI    *UserInterface `json:"ui,omitempty"`
	// contains filtered or unexported fields
}

AuthProvider authenticates requests the SAML Response to the SP Assertion Consumer Service using the HTTP-POST Binding.

func (AuthProvider) Authenticate

func (m AuthProvider) Authenticate(w http.ResponseWriter, r *http.Request) (caddyauth.User, bool, error)

Authenticate validates the user credentials in and returns a user identity, if valid.

func (AuthProvider) CaddyModule

func (AuthProvider) CaddyModule() caddy.ModuleInfo

CaddyModule returns the Caddy module information.

func (*AuthProvider) Provision

func (m *AuthProvider) Provision(ctx caddy.Context) error

Provision provisions SAML authentication provider

func (*AuthProvider) Validate

func (m *AuthProvider) Validate() error

Validate implements caddy.Validator.

type AzureIdp

type AzureIdp struct {
	CommonParameters
	Enabled             bool                       `json:"enabled,omitempty"`
	ServiceProviders    []*samllib.ServiceProvider `json:"-"`
	IdpMetadataLocation string                     `json:"idp_metadata_location,omitempty"`
	IdpMetadataURL      *url.URL                   `json:"-"`
	IdpSignCertLocation string                     `json:"idp_sign_cert_location,omitempty"`
	TenantID            string                     `json:"tenant_id,omitempty"`
	ApplicationID       string                     `json:"application_id,omitempty"`
	ApplicationName     string                     `json:"application_name,omitempty"`

	// LoginURL is the link to Azure AD authentication portal.
	// The link is auto-generated based on Azure AD tenant and
	// application IDs.
	LoginURL string `json:"-"`
	// EntityID is the "Identifier (Entity ID)" an administrator
	// specifies in "Set up Single Sign-On with SAML" in Azure AD
	// Enterprise Applications.
	EntityID string `json:"entity_id,omitempty"`
	// AcsURL is the list of URLs server instance is listening on. These URLS
	// are known as SP Assertion Consumer Service endpoints. For example,
	// users may access a website via http://app.domain.local. At the
	// same time the users may access it by IP, e.g. http://10.10.10.10. or
	// by name, i.e. app. Each of the URLs is a separate endpoint.
	AssertionConsumerServiceURLs []string `json:"acs_urls,omitempty"`
	// contains filtered or unexported fields
}

AzureIdp authenticates request from Azure AD.

func (*AzureIdp) Authenticate

func (az *AzureIdp) Authenticate(r *http.Request) (*caddyauth.User, string, error)

Authenticate parses and validates SAML Response originating at Azure Active Directory.

func (*AzureIdp) Validate

func (az *AzureIdp) Validate() error

Validate performs configuration validation

type CommonParameters

type CommonParameters struct {
	AuthURLPath    string          `json:"auth_url_path,omitempty"`
	SuccessURLPath string          `json:"success_url_path,omitempty"`
	Jwt            TokenParameters `json:"jwt,omitempty"`
}

CommonParameters represent a common set of configuration settings, e.g. authentication URL, Success Redirect URL, JWT token name and secret, etc.

type TokenParameters

type TokenParameters struct {
	TokenName   string `json:"token_name,omitempty"`
	TokenSecret string `json:"token_secret,omitempty"`
	TokenIssuer string `json:"token_issuer,omitempty"`
}

TokenParameters represent JWT parameters of CommonParameters.

type UserClaims

type UserClaims struct {
	Audience  string   `json:"aud,omitempty"`
	ExpiresAt int64    `json:"exp,omitempty"`
	ID        string   `json:"jti,omitempty"`
	IssuedAt  int64    `json:"iat,omitempty"`
	Issuer    string   `json:"iss,omitempty"`
	NotBefore int64    `json:"nbf,omitempty"`
	Subject   string   `json:"sub,omitempty"`
	Name      string   `json:"name,omitempty"`
	Email     string   `json:"email,omitempty"`
	Roles     []string `json:"roles,omitempty"`
	Origin    string   `json:"origin,omitempty"`
}

UserClaims represents custom and standard JWT claims.

func (UserClaims) AsMap

func (u UserClaims) AsMap() map[string]interface{}

AsMap converts UserClaims struct to dictionary.

func (UserClaims) Valid

func (u UserClaims) Valid() error

Valid validates user claims.

type UserInterface

type UserInterface struct {
	TemplateLocation   string              `json:"template_location,omitempty"`
	AllowRoleSelection bool                `json:"allow_role_selection,omitempty"`
	Template           *template.Template  `json:"-"`
	Title              string              `json:"title,omitempty"`
	LogoURL            string              `json:"logo_url,omitempty"`
	LogoDescription    string              `json:"logo_description"`
	Links              []userInterfaceLink `json:"-"`
	AuthEndpoint       string              `json:"-"`
	LocalAuthEnabled   bool                `json:"local_auth_enabled"`
}

UserInterface represents a set of configuration settings for user interface and associated methods

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL