Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 6 Current »

Requirements

  • NGINIX Plus (NGINX Plus)

  • SurePassID Identity Provider

Install

Follow the nginx-openid-connect installation instructions.
NGINX (nginx-openid-connect) - Installation

Install the jq command-line JSON processor. There is a dependency for this but it is not automatically installed.

  • sudo yum install jq

SELinux Issue Workaround

There is an issue with NGINIX’s permissions for the directory “/etc/nginx/conf.d". The simplest workaround for this is to change the owner and group of that directory to "nginix".

  • sudo chown ngnix:ngnix /etc/nginx/conf.d

A better solution would be to fix SELinux httpd_t context to allow the nginix process to create files in that directory.
https://www.nginx.com/blog/using-nginx-plus-with-selinux/

Configuring the SurePassID Identity Provider

NGINX (nginx-openid-connect) - Configuring your IdP

NGINX OpenID Connect Client Configuration

Use the following SurePassID Identity Provider OpenID Connect client configuration for the NGNIX replying party.

Update the following properties as required.

  • ClientId

  • ClientName

  • ClientSecrets.Value

  • RedirectUris

  • PostLogoutRedirectUris

  • Properties.*

See Client Object Reference for more details.

 NGINX OpenID Connect Client
{
    "Enabled": true,
    "ProtocolType": "oidc",
    "ClientId": "nginx-client-id",
    "ClientName": "NGINX Client Name",
    "ClientSecrets": [
        {
            "Value": "bmdpbngtY2xpbmV0LXNlY3JldA==",
            "Type": "SharedSecret"
        }
    ],
    "AllowedGrantTypes": [
        "authorization_code"
    ],
    "RedirectUris": [
        "https://app-proxy.example.com/_codexch"
    ],
    "PostLogoutRedirectUris": [
        "https://app-proxy.example.com/_logout"
    ],
    "RequireClientSecret": true,
    "RequireConsent": true,
    "AllowRememberConsent": true,
    "RequirePkce": false,
    "AllowPlainTextPkce": false,
    "AllowAccessTokensViaBrowser": false,
    "FrontChannelLogoutSessionRequired": true,
    "BackChannelLogoutSessionRequired": true,
    "AllowOfflineAccess": false,
    "AllowedScopes": [
        "profile",
        "openid"
    ],
    "AlwaysIncludeUserClaimsInIdToken": true,
    "IdentityTokenLifetime": 300,
    "AccessTokenLifetime": 3600,
    "AuthorizationCodeLifetime": 300,
    "AbsoluteRefreshTokenLifetime": 2592000,
    "SlidingRefreshTokenLifetime": 1296000,
    "RefreshTokenUsage": 1,
    "UpdateAccessTokenClaimsOnRefresh": false,
    "RefreshTokenExpiration": 1,
    "AccessTokenType": 0,
    "EnableLocalLogin": true,
    "IdentityProviderRestrictions": [],
    "IncludeJwtId": false,
    "Claims": [],
    "AlwaysSendClientClaims": false,
    "ClientClaimsPrefix": "client_",
    "DeviceCodeLifetime": 300,
    "AllowedCorsOrigins": [],
    "Properties": {
        "MfaButtons.ALL": "PushApp,IvrQuestion,SmsQuestion,SmsOtp,EmailOtp,CallWithOtp",
        "MfaButtonsDefault": "SmsOtp,EmailOtp,CallWithOtp",
        "AllowOtpDefault": "true",

        "TenantDomain.0": "tenant0.com",
        "TenantId.0": "<TENANT_0_API_ID>",
        "TenantKey.0": "<TENANT_0_API_KEY>",
        "TenantAllowOtp.0": "true",
        "TenantMfaButtons.0": "PushApp,IvrQuestion,SmsQuestion",

        "TenantDomain.1": "tenant1.com",
        "TenantId.1": "<TENANT_1_API_ID>",
        "TenantKey.1": "<TENANT_1_API_KEY>",
        "TenantAllowOtp.1": "true",
        "TenantMfaButtons.1": "PushApp,IvrQuestion,SmsQuestion,SmsOtp,EmailOtp,CallWithOtp"
    }
}

Configuring NGINIX Plus

NGINX (nginx-openid-connect) - Configuring NGINX Plus

Run the configure.sh script using the SurePassID OpenID Connect Discovery URL.

  • ./configure.sh https://oidc.surepassid.com/.well-known/openid-configuration

Make the following changes to the openid_connect_configuration.conf file.

  • Added the following end session endpoint mapping.

    map $host $oidc_endsession_endpoint {
        default https://oidc.surepassid.com/connect/endsession;
    }
  • Add the following to the file so that the JWKS URL can be used to automatically keep the keys up-to-date.

    map $host $oidc_jwks_uri {
        default https://oidc.surepassid.com/.well-known/openid-configuration/jwks;
    }
  • Set the Client ID and Client Secret in the mappings as shown.

    map $host $oidc_client {
        default "<OIDC_CLIENT_ID>";
    }
    map $host $oidc_client_secret {
        default "<OIDC_CLIENT_SECRET>";
    }
  • Modify the $oidc_logout_redirect to use the URI "/oidc_logout". This will be configured in the next section

    map $host $oidc_logout_redirect {
        # Where to send browser after requesting /logout location. This can be
        # replaced with a custom logout page, or complete URL.
        default "/oidc_logout";
    }

This is a complete example of the updated openid_connect_configuration.conf file.

 openid_connect_configuration.conf
# OpenID Connect configuration
#
# Each map block allows multiple values so that multiple IdPs can be supported,
# the $host variable is used as the default input parameter but can be changed.
#
map $host $oidc_authz_endpoint {
    default https://oidc.surepassid.com/connect/authorize;
}

map $host $oidc_token_endpoint {
    default https://oidc.surepassid.com/connect/token;
}

map $host $oidc_endsession_endpoint {
    default https://oidc.surepassid.com/connect/endsession;
}
map $host $oidc_jwks_uri {
    default https://oidc.surepassid.com/.well-known/openid-configuration/jwks;
}

map $host $oidc_jwt_keyfile {
    default conf.d/idp_jwk.json;
}

map $host $oidc_client {
    default "<OIDC_CLIENT_ID>";
}

map $host $oidc_pkce_enable {
    default 0;
}

map $host $oidc_client_secret {
    default "<OIDC_CLIENT_SECRET>";
}

map $host $oidc_scopes {
    default "openid+profile+email+offline_access";
}

map $host $oidc_logout_redirect {
    # Where to send browser after requesting /logout location. This can be
    # replaced with a custom logout page, or complete URL.
    default "/oidc_logout";
}

map $host $oidc_hmac_key {
    # This should be unique for every NGINX instance/cluster
    default <UNIQUE_GENERATED_OIDC_HMCA_KEY>;
}

map $proto $oidc_cookie_flags {
    http  "Path=/; SameSite=lax;"; # For HTTP/plaintext testing
    https "Path=/; SameSite=lax; HttpOnly; Secure;"; # Production recommendation
}

map $http_x_forwarded_port $redirect_base {
    ""      $proto://$host:$server_port;
    default $proto://$host:$http_x_forwarded_port;
}

map $http_x_forwarded_proto $proto {
    ""      $scheme;
    default $http_x_forwarded_proto;
}

# ADVANCED CONFIGURATION BELOW THIS LINE
# Additional advanced configuration (server context) in openid_connect.server_conf

# JWK Set will be fetched from $oidc_jwks_uri and cached here - ensure writable by nginx user
proxy_cache_path /var/cache/nginx/jwk levels=1 keys_zone=jwk:64k max_size=1m;

# Change timeout values to at least the validity period of each token type
keyval_zone zone=oidc_id_tokens:1M state=conf.d/oidc_id_tokens.json timeout=1h;
keyval_zone zone=refresh_tokens:1M state=conf.d/refresh_tokens.json timeout=8h;
keyval_zone zone=oidc_pkce:128K timeout=90s; # Temporary storage for PKCE code verifier.

keyval $cookie_auth_token $session_jwt zone=oidc_id_tokens;   # Exchange cookie for JWT
keyval $cookie_auth_token $refresh_token zone=refresh_tokens; # Exchange cookie for refresh token
keyval $request_id $new_session zone=oidc_id_tokens; # For initial session creation
keyval $request_id $new_refresh zone=refresh_tokens; # ''
keyval $pkce_id $pkce_code_verifier zone=oidc_pkce;

auth_jwt_claim_set $jwt_audience aud; # In case aud is an array
js_import oidc from conf.d/openid_connect.js;

# vim: syntax=nginx

Make the following changes to the frontend.conf file. This is where the backend application server is configured.

  • Configure the upstream (backend) servers.
    upstream directive

    upstream backend_app_server {
        zone backend_app_server 64k;
    
        # Server Private IP Address
        server 10.1.2.3:443;
    
        # DNS
        #resolver 8.8.8.8;
        #server app-proxy.example.com:443;
    }
  • If applicable, configure SSL.
    http://nginx.org/en/docs/http/ngx_http_ssl_module.html

    server {
        ...
    
        #####################
        # SSL Configuration #
        #####################
        server_name  app-proxy.example.com;
        listen       443 ssl;
    
        ssl_certificate     ssl/example.com.crt;
        ssl_certificate_key ssl/example.com.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
    
        ...
    }
  • Add the /oidc_logout location. Place this in the server block before the / location.

    server {
        ...
    
        location = /oidc_logout {
            # https://identityserver4.readthedocs.io/en/latest/endpoints/endsession.html
            proxy_ssl_server_name on; # For SNI to the IdP
            # $oidc_endsession_endpoint?  // Defined in openid_connect_configuration.conf
            #   id_token_hint=$arg_token&
            #   post_logout_redirect_uri=https://app-proxy.example.com:433/_logout // The URL value must be URL encoded.
            proxy_pass $oidc_endsession_endpoint?id_token_hint=$arg_token&post_logout_redirect_uri=https%3a%2f%2fapp-proxy.example.com%3a433%2f_logout;
        }
    
        location / {
            ...
        }
    }
  • Configure the reverse proxy to the backend application server.

    server {
        ...
        
        location / {
            # This site is protected with OpenID Connect
            auth_jwt "" token=$session_jwt;
            error_page 401 = @do_oidc_flow;
    
            #auth_jwt_key_file $oidc_jwt_keyfile;  # Enable when using filename
            auth_jwt_key_request /_jwks_uri;       # Enable when using URL
    
            # Successfully authenticated users are proxied to the backend,
            # with 'sub' claim passed as HTTP header
            proxy_set_header username $jwt_claim_sub;
            proxy_pass https://backend_app_server; # The backend site/app
    
            proxy_set_header Host app-proxy.example.com;
            proxy_cookie_domain app-proxy.example.com $host;
        }
    }

This is a complete example of the updated frontend.conf file.

 Click here to expand...
# This is the backend application we are protecting with OpenID Connect
upstream backend_app_server {
    zone backend_app_server 64k;

    # Private Azure IP
    server 10.1.2.3:443;

    # DNS
    #resolver 8.8.8.8;
    #server app-proxy.example.com:443;
}

# Custom log format to include the 'sub' claim in the REMOTE_USER field
log_format main_jwt '$remote_addr - $jwt_claim_sub [$time_local] "$request" $status '
                    '$body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';

# The frontend server - reverse proxy with OpenID Connect authentication
#
server {
    include conf.d/openid_connect.server_conf; # Authorization code flow and Relying Party processing
    error_log /var/log/nginx/error.log debug;  # Reduce severity level as required

    #####################
    # SSL Configuration #
    #####################
    server_name  app-proxy.example.com;
    listen       443 ssl;

    ssl_certificate     ssl/surepassid.com_2022-05-14.crt;
    ssl_certificate_key ssl/surepassid.com_2022-05-14.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    location = /oidc_logout {
        # https://identityserver4.readthedocs.io/en/latest/endpoints/endsession.html
        proxy_ssl_server_name on; # For SNI to the IdP
        proxy_pass $oidc_endsession_endpoint?id_token_hint=$arg_token&post_logout_redirect_uri=https%3a%2f%2fapp-proxy.example.com%3a433%2f_logout;
    }

    location / {
        # This site is protected with OpenID Connect
        auth_jwt "" token=$session_jwt;
        error_page 401 = @do_oidc_flow;

        #auth_jwt_key_file $oidc_jwt_keyfile;  # Enable when using filename
        auth_jwt_key_request /_jwks_uri;       # Enable when using URL

        # Successfully authenticated users are proxied to the backend,
        # with 'sub' claim passed as HTTP header
        proxy_set_header username $jwt_claim_sub;
        proxy_pass https://backend_app_server; # The backend site/app

        proxy_set_header Host app-proxy.example.com;
        proxy_cookie_domain app-proxy.example.com $host;
    }
}

# vim: syntax=nginx
  • No labels