The CreatorCon Call for Content is officially open! Get started here.

ARG645
Tera Guru

One of the most commonly used authentication mechanisms when you consume or produce a web service is Basic Authentication.  Basic Authentication requires two credentials

  1. UserID
  2. Password

If your requirement is to allow a 3rd party application to use OAuth2 authentication to consume service-now's web service, then you will need to setup OAuth credentials in the application registry which include ClientID, Client Secret, Default Grant Type etc. Along with the OAuth specific credentials, you will also need a UserID and Password of a user account (sys_user record) that has access to the resources in ServiceNow.  

I ran into this special situation when I created a Scripted Rested API to allow a 3rd party application to consume my Web Service. The 3rd party application was using OAuth2 Authentication, obviously I used credentials like Client Secret and ClientID and, the UserID and Password of my User Account which has access to read/write to one of my tables. Everything was developed and the integration was working perfect.

After few days I have seen some questions in the community which pointed out that you can still make API  calls by using Basic Authentication and bypass OAuth2 authentication. That’s True, may be that’s by design, but the real question is “How to restrict an endpoint in ServiceNow from Basic Authentication?”.  The whole point of using OAuth2 is to provide better authentication via access tokens, refresh tokens, client id, secrets and UserID/password of a service account. If somebody gets hold of my UserID and Password of my Service Account, and if they successfully send a request using Basic Auth from a REST client like PostMan or ARC, then the whole point of setting up OAuth Authentication is useless.

If you are in a similar situation, below is the work around.

  1. Create a system property
    1. Named: restricted.basic-auth.endpoints
    2. Type: string
    3. Value: comma separated list of endpoints you want to restrict from Basic Authentication.

Example screen shot:

 find_real_file.png

  1. Modify the OOB Script include named BasicAuth
    1. Modifying an OOB Script include is not recommended, if possible De-Activate the existing OOB Script include and create a new one with the same name.
    2. Below is Script for the script include [Added a function named isrestricted and this function will be called in another function named getAuthorized to check if the endpoint in the request is restricted for Basic Authentication or not]
      var BasicAuth = Class.create();
      
      BasicAuth.prototype = {
      	initialize : function(request, response, auth_type, auth_value) {
      		this.request = request;
      		this.response = response;
      		this.auth_type = auth_type;
      		this.auth_value = auth_value;
      	},
      	
      	getAuthorized : function() {
      		/* Mechanism to restrict certain endpoints from Basic Authentication */
      		var checkIfRestricted = this.isrestricted();
      		if(checkIfRestricted)
      			{
      			return null;
      		}
      		
      		var up = GlideStringUtil.base64Decode(this.auth_value);
      		var split = up.indexOf(":");
      		
      		if (split == -1) {
      			gs.log("Basic authentication not well formed");
      			return null;
      		}
      		
      		// locate user and impersonate
      		var userName = up.substring(0, split);
      		var password = up.substring(split + 1);
      		var result = GlideUser.authenticateUser(userName, password);
      		
      		if (!result) {
      			gs.log("Basic authentication failed for user: " + userName);
      			return null;
      		}
      		
      		// user is authenticated, so return it...
      		return result;
      	},
      	
      	isrestricted : function(){
      		var endpointsString = gs.getProperty("restricted.basic-auth.endpoints");
      		var endpointsArray = endpointsString.split(",");
      		var incomingRequestURL = this.request.getRequestURI()+'';
      		if(endpointsArray.indexOf(incomingRequestURL) > -1)
      			return true;
      		else
      			return false;
      	}
      }​

       

You can scale the above work around to you requirements, but remember : getAuthorized() function in the above script include is used by many other OOB or your custom processes to use Basic Authentication. If you are trying to shape the above work around for your own requirements DO NOT PERFORM GLIDE RECORD OPERATIONS in this script include as it can cause performance impacts. That is the whole reason to use a system property which is lighter than a table read to check for specific endpoints and restrict them from Basic Authentication. 

Comments
Dave Bourland
ServiceNow Employee
ServiceNow Employee

Thanks for the info Aman.  When you mentioned "service account" was that the account used for your Oauth?  Did you require oauth for all users on your servicenow instance?  I would think if you did that, then basic auth wouldn't work since that holds true when enabling MFA for a user...thanks!

Dave Bourland
ServiceNow Employee
ServiceNow Employee

One more question - could I use the ACL's for the API's (listed here) to help mitigate who has access?  Have you used these before?  thanks!

ARG645
Tera Guru

David, 

Below are my answers for your questions 

When you mentioned "service account" was that the account used for your Oauth?

Answer: Yes. for OAuth of Grant Type "Password" /"Resource Owner Password Grant" we need to provide UserID and Password (Mostly considered as Service Account)

 

Did you require oauth for all users on your servicenow instance? 

Answer: NO, users logged in normally into the instance by providing their credentials. But for some of the integrations, we had service accounts (a record in sys_user table with necessary roles who need a Non Interactive Session)

ARG645
Tera Guru

David,

 

I used ACL of type REST_Endpoint in the Scripted API resource to check if the User who is trying to Authenticate has appropriate roles or not. (OOB Example you can check is an ACL with Name "Scripted REST External Default")

As an endpoint is subjected to a Non Interactive Session, Defining Read/Write ACL's is not appropriate. So defining ACL's of Operation Execute would do the job as it determines who can execute scripts against a particular table.  

 

Thank you,

Aman Gurram

quiksilver
Mega Guru

Hi Aman,

 

I am trying to do the same thing.  Can you help me understand how to relate the user record to the OAuth credentials created in the application registry ? 

 

If your requirement is to allow a 3rd party application to use OAuth2 authentication to consume service-now's web service, then you will need to setup OAuth credentials in the application registry which include ClientID, Client Secret, Default Grant Type etc. Along with the OAuth specific credentials, you will also need a UserID and Password of a user account (sys_user record) that has access to the resources in ServiceNow.  

 

THanks

 

quik

ARG645
Tera Guru

quiksilver,

There is no direct connection from User Record to OAuth Credentials in Application registry. The USer record should have access to the target resources and make sure Web service access only checkBox is checked. 

That should allow your user (service Account) to start a Non-interactive session. 

Thank you,

Aman Gurram

quiksilver
Mega Guru

Hi Aman,

 

Thanks for your reply.

 

Will this solution work for OOTB Table API or only for Scripted REST API ? 

 

Cheers

Quik

ARG645
Tera Guru

Quik,

It should also work for OOB Table API's.

Thanks,

Aman

miriamberge
Tera Guru

 

This is great.  Thank you!

Correct me if I'm wrong, but if I set the OOB script include to false and create a new one as above, when I go to upgrade if there were any changes made to the OOB script, it will get marked as SKIPPED... is that correct?  I can live with reviewing the changes made to the OOB script during an upgrade if it means that we can enforce Oauth.  🙂

 

ARG645
Tera Guru

You are right. 

lukas-slansky
Tera Guru

Yes, the record would be marked as skipped - it is changed (the Active field).

Abaranji
Tera Explorer

Hi Aman,

How its works for OAuth credentials. How it validate the OAuth users.

Requirement :  I have scripted API POST Method its basically authentication with username and password but i am looking for OAuth credentials instead of basic authentication

 

Could you please help me out.

 

avivs
Tera Expert

Hi Aman

I have Scripted Rest API which should be consumed by OAuth only, but the grand type is Client Credentials so no any service account.
How I can solve this? 

Brendanh
Tera Contributor

For people that come here in the future, I believe that API access policies is an OOB feature that should handle this going forward, rather than creating something custom.

 

> API access policy defines the permissions and duration of access to an API.

> API access policy enables you to restrict access to inbound ServiceNow® APIs based on the authentication type and the specified filter criteria of the access policy.

 

Create REST API access policy 

Version history
Last update:
‎12-30-2018 01:51 AM
Updated by: