Skip to main content

Tutorial: Implementing a Post-Auth Script in Access Server

Abstract

Programmatically manage Access Server's authentication processes with a post-auth script. This tutorial teaches you how.

Overview

Post-authentication scripts in Access Server allow you to manage authentication processes programmatically. You can use these scripts to extend or modify the behavior of Access Server’s authentication mechanisms, such as implementing additional checks or assigning specific user properties.

This tutorial covers script parameters and tips for writing and testing your scripts.

Note

OpenVPN Inc. provides examples of post-auth scripts, but we don't offer custom ones. Use the example scripts and documentation provided to develop or modify the post-auth script using the Python3 programming language.

  • An installed Access Server.

  • Python3 installed.

  • Basic knowledge of Python scripting.

  • Console access and the ability to get root access.

Access Server's post-auth scripts allow you to:

  • Handle or modify authentication after Access Server's initial authentication.

  • Apply additional checks, conditions, or restrictions for users.

  • Use only one post-auth script at a time.

  • Modify attributes such as group assignment, IP addresses, and other client properties.

  • If AUTH_NULL is set to true, the script handles authentication (custom authentication method).

The basic function of the post-auth script looks like this:

def post_auth(authcred, attributes, authret, info):
    # Custom authentication logic here
    return authret

Access Server handles authentication first (e.g., through RADIUS, LDAP, SAML, or local authentication) and then passes control to the post-auth function for further processing. If you implement the custom authentication method, the post-auth script handles authentication.

Post-auth scripts take several parameters, including:

  • authcred: Contains the user's credentials such as username and client IP.

  • attributes: Contains client-reported values such as client version and platform.

  • authret: Contains the authentication status, which you can modify to succeed or fail the authentication.

  • info: Provides additional details depending on the authentication method used (e.g., LDAP, SAML).

Tip

If you make authentication decisions based on username, use authret[‘user’], as that is the normalized version after going through the authentication process. The value authcred[‘username’] is what the user enters unchanged.

authcred: a dictionary containing the following items:

Parameter

Type

Required

Description

username

string

true

The VPN client username provided by the end user.

client_ip_addr

string

true

VPN client's real IP address.

client_hw_addr

string

false

Default gateway interface MAC address of the VPN client's UUID.

static_response

string

false

A string entered by the user in response to a custom challenge question.

attributes: a dictionary that can contain client-reported values:

Parameter

Type

Required

Description

client_info

dictionary of strings

Provided by the client and includes the strings below.

> UV_ASCLI_VER

The version number of the connecting Access Server client.

> IV_PLAT

The client platform: win = Windows, mac = macOS, linux = Linux, ios = iOS, android = Android.

> UV_PLAT_REL

The client platform's specific version.

> UV_APPVER_<APP_NAME>

The version number of APP_NAME installed on the client.

> IV_HWADDR

The primary network interface MAC address or UUID.

vpn_auth

boolean

false

True if this is VPN authentication; absent if a non-VPN authentication path was used (such as web server access).

reauth

boolean

false

True if this is a VPN mid-session authentication, false if it's an initial VPN authentication, and absent for non-VPN authentications.

authret: a dictionary containing the authentication status, may be modified and returned by the script

If the script returns authret unmodified, there’s no effect on the authentication process, i.e., authentication proceeds as if the script isn’t present. However, by modifying authret, the script can affect these changes in the authentication process:

  1. Failing authentication setting 'status' item to FAIL.

  2. When authentication fails, generate failure strings and add them to the log file ('reason' item) or push them to the client for display to the end user ('client_reason' item).

  3. Set or change the properties of the client instance object on the server, including group, IP address, and other properties.

Parameter

Type

Required

Description

status

int

true

This value is passed to the post-auth script and can be altered to override the authentication status. This lets the script decide whether the authentication attempt fails or succeeds.

These are the three possible states:

  • 0 = SUCCEED

  • 1 = FAIL

  • 5 - NEED_TWOFACTOR_ENROLLMENT (available since Access Server 2.14.0)

Note

If you change the status from 5 (NEED_TWOFACTOR_ENROLLMENT) state to 0 (SUCCEED), you will bypass the requirement to enroll for MFA for the authentication session and make the session fully authenticated.

Tip

If you want to use the names instead of the numbers to return the value, you must add the following to the script to import those symbols:

from pyovpn.plugin import *

user

string

true

The canonical username of the user. In some cases, this username may differ from the username in authcred, such as LDAP case-insensitive matching. When you use LDAP authentication, this is the username reported by the LDAP server, while authcred['username'] is the username entered by the user.

reason

string

false

On auth failure, this string will be output to the log file for diagnostic purposes.

client_reason

string

false

On authentication failure, this string will be sent to the VPN client and will be shown to the user in an error dialog box.

proplist

dictionary

false

A list of user properties for the connecting user. In most cases, you only need to set the conn_group member since the group can define all other properties.

conn_group

string

Designate this user as a member of the given group.

Tip

When setting conn_group in the script, you should generally include GROUP_SELECT = True in your script's top-level, global section. This tells Access Server to do a late user properties lookup so that the user properties are taken from the group chosen by the post-auth script. Additionally, any user properties returned by the script in authret['proplist'] override those read from the user properties database.

conn_ip

string: IP address

The dynamic IP address that should be assigned to the user. Ensure this IP address exists within a group subnet. If conn_group (above) isn't specified, Access Server tries to derive the group by looking at the set of all groups and finding the group for which this IP address is contained within group_subnets.

prop_superuser

boolean

Designate as an Access Server administrator.

prop_autogenerate

boolean

Allow standard user-login profiles.

prop_autogenerate

boolean

Allow autologin profiles.

prop_autologin

boolean

Allow auto-login profiles.

prop_deny_web

boolean

Deny access to the client web server and XML/REST web services (but still allow VPN access).

prop_lzo

boolean

Enable lzo compression (deprecated).

prop_reroute_gw_override

string

> disable

Disable reroute_gw for this client.

> dns_only

Disable reroute_gw for this client, but still route DNS.

> global

Use global reroute_gw setting (default).

> prop_expire

int

The maximum duration of non-autologin sessions (in seconds) before reauth is required. 0 = infinite.

> prop_expire_halt

boolean

If true, the VPN client is halted on prop_expire expiration rather than being allowed to reauth.

Info

The info dictionary contains the following members, depending on the current auth_method:

> auth_method

string

Contains the auth method and may contain special auth methods such as autologin (certificate-only auth).

  • local

  • pam

  • ldap

  • radius

  • saml

  • pas_only

LDAP specific

> ldap_context

object

You can use This Python LDAP context object to perform additional LDAP queries. We use this in our LDAP group mapping script.

> user_dn

string

The LDAP distinguished name of the user that is authenticating. Access Server uses this to normalize the username to what the LDAP server reports.

RADIUS specific

> radius_reply

dictionary

Attributes received from the RADIUS server as part of the successful authentication reply. We use this in our RADIUS group mapping script.

SAML specific

> saml_attr

dictionary

Attributes received from the SAML server as part of the successful authentication reply.

Return value

The post-auth function must return either authret or (authret, proplist_save).

Returning only authret affects only the current authentication session and doesn't store data permanently. Returning an optional proplist_save dictionary with key/value pairs allows storing data in the user properties database for later use. We use this in our hardware-address checking script.

The post-auth script must include the following basic structure:

from pyovpn.plugin import *

def post_auth(authcred, attributes, authret, info):
    # Example: Check if the user is part of a specific group
    if authcred['username'] == 'admin':
        authret['conn_group'] = 'admin_group'
        authret['status'] = SUCCEED
    else:
        authret['conn_group'] = 'default_group'
    
    return authret

This example assigns the admin_group to the user admin, while all other users are assigned to default_group.

To test the post-auth script, first install the script then test it with the authcli tool:

  1. Connect to your console and get root privileges.

  2. Use the authcli tool to simulate authentication:

    ./authcli -u test_user
  3. Enter the password when prompted.

    • Authentication results are returned, including any modifications made by your script.

    • Example output:

      API METHOD: authenticate
      Password: <password>
      AUTH_RETURN
        status : SUCCEED
        user : test_user
        conn_group : default_group