Authentication¶
Basic Authentication¶
Standard BasicAuth, every request contains your username and password base64 encoded in the request header. The most insecure, but simplest, way to authenticate. Remember to scope the user’s ACLs to the minimum if using with automations.
>>> client = pysnc.ServiceNowClient('dev00000', ('admin','password'))
This is not recommended for any production or machine to machine activity
OAuth2 - Password Grant Flow¶
OAuth2 password flow is currently supported and recommended
>>> from pysnc import ServiceNowClient
>>> from pysnc.auth import ServiceNowPasswordGrantFlow
>>> client_id = 'ac0dd3408c1031006907010c2cc6ef6d' # oauth_entity.client_id
>>> secret = '...' # oauth_entity.client_secret
>>> auth = ServiceNowPasswordGrantFlow(username, password, client_id, secret))
>>> client = ServiceNowClient(server_url, auth)
This will use a users credentials to retrieve and store an OAuth2 auth and refresh token, sending your auth token with every request and dropping your user and password from memory. This will automatically update your access tokens.
To configure this flow, create a new OAuth Application by selecting a new OAuth API endpoint:
Name it, save/insert it, and note your new client_id and client_secret. This flow is sometimes called a Legacy flow, as it is not the ideal method OAuth usage. In this flow it is tolerable to share/embed your client_secret.
OAuth2 - Auth Code Grant Flow¶
No instructions, currently. Typically what you would want to use if you’re a client doing things on behalf of users.
OAuth2 - Client Credential Grant Flow¶
ServiceNow does not support this OAuth flow
OAuth2 - JWT Bearer Grant Flow¶
Create a new JWT Provider and use it with whomever generates your JWT tokens. Once you have your JWT you may use it to request a Bearer token for standard auth:
>>> auth = ServiceNowJWTAuth(client_id, client_secret, token)
>>> client = ServiceNowClient(self.c.server, auth)
Wherein client_id and client_secret are the oauth_jwt record entry values and token is the JWT generated by your provider.
The token contains who are are logging in as - as such the PySNC library does not attempt to act as a provider. We do however have an example of how that is done in the tests.
mTLS - Mutual TLS Authentication (Certificate-Based Authentication)¶
The most ideal form of authentication for machine to machine communication. Follow KB0993615 then:
>>> client = ServiceNowClient(instance, cert=('/path/to/USER_x509.pem', '/path/to/USERPRIVATEKEY.key'))
A quick example, using self-signed certificates:
Setup the CA (root) key
# generate a root private key, if for some reason you don't have one already
openssl genrsa -aes256 -out ca.key 2048
# generate the CA certificate
openssl req -x509 -new -nodes -key ca.key -out cert.pem -sha512 -days 365 -out cacert.pem
Upload cacert.pem via /sys_ca_certificate.do
Setup the user key and CSR (we just generate them here for a POC example)
openssl req -nodes -newkey rsa:2048 -keyout USERPRIVATEKEY.key -out USERCSR.csr
Important
Python requests (the underlying http library) does not directly support keys with passwords! See requests#2519 for details.
Sign the CSR with the root, creating a X.509 for the user
openssl x509 -req -days 365 -in USERCSR.csr -CA cacert.pem -CAkey ca.key -extfile <(printf "extendedKeyUsage=clientAuth") -out USER_x509.pem
Attach USER_x509.pem to a new /sys_user_certificate.do record
Requests Authentication¶
Ultimately any authentication method supported by python requests (https://2.python-requests.org/en/master/user/authentication/) can be passed directly to ServiceNowClient.
Should be flexible enough for any use-case.
Storing Passwords¶
The keystore module is highly recommended. For example:
import keyring
def check_keyring(instance, user):
passw = keyring.get_password(instance, user)
return passw
def set_keyring(instance, user, passw):
keyring.set_password(instance, user, passw)
if options.password:
passw = options.password
set_keyring(options.instance, options.user, passw)
else:
passw = check_keyring(options.instance, options.user)
if passw is None:
print('No Password specified and none found in keyring')
sys.exit(1)
client = pysnc.ServiceNowClient(options.instance, ...)