Hello @chrisp,
Take a look at this rule implemented for custom authentication on a Web Service source. You can use this as a connector rule in the beforeOperationRule on any operation where the custom authentication is needed.
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule language="beanshell" name="Custom Authentication" type="WebServiceBeforeOperationRule">
<Description>
This rule is used by the Web Services connector before performing any operation like testconnection,
aggregation etc.
</Description>
<Signature returnType="EndPoint">
<Inputs>
<Argument name="log">
<Description>
The log object associated with the SailPointContext.
</Description>
</Argument>
<Argument name="context">
<Description>
A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
</Description>
</Argument>
<Argument name="application">
<Description>The application whose data file is being processed.</Description>
</Argument>
<Argument name="requestEndPoint">
<Description>The current request information contain header, body, context url, method type, response attribute map,
successful response code
</Description>
</Argument>
<Argument name="oldResponseMap">
<Description>earlier response object </Description>
</Argument>
<Argument name="restClient">
<Description>REST Client Object</Description>
</Argument>
</Inputs>
<Returns>
<Argument name="EndPoint">
<Description>Updated EndPoint Object</Description>
</Argument>
</Returns>
</Signature>
<Source><![CDATA[
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.lang.JoseException;
import org.json.JSONException;
import org.json.JSONObject;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Map;
public String generateToken() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, JoseException {
java.security.Security.addProvider(new BouncyCastleProvider());
// Creating instance of PEM reader to get the Secret Key
PemReader pemReader = new PemReader(new StringReader(SECRET_KEY));
PemObject pemObject;
pemObject = pemReader.readPemObject();
//Getting the RSA instance for KeyFactory
KeyFactory factory = KeyFactory.getInstance("RSA");
byte[] content = pemObject.getContent();
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
RSAPrivateKey privateKey = (RSAPrivateKey) factory.generatePrivate(privKeySpec);
//Getting the Unix time for UTC
long unixTime = Instant.now().getEpochSecond();
//Adding a minute to Unix time UTC
long unixTime1 = Instant.now().plus(1, ChronoUnit.MINUTES).getEpochSecond();
JwtClaims claims = new JwtClaims();
claims.setClaim("iss","<issuer>");
claims.setClaim("aud","<aud_value>");
claims.setClaim("scope","<scopes>");
claims.setClaim("iat",unixTime);
claims.setClaim("exp",unixTime1);
JsonWebSignature jws = new JsonWebSignature();
jws.setDoKeyValidation(false);
jws.setPayload(claims.toJson());
jws.setKey(privateKey);
jws.setAlgorithmHeaderValue("RS256");
return jws.getCompactSerialization();
}
private String jsonObjectCreator( String token) throws JSONException {
log.error("Custom Auth Rule : Inside jsonObjectCreator()" );
JSONObject obj=new JSONObject();
obj.put("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
obj.put("assertion", token);
String json = obj.toString();
log.error("Custom Auth Rule : The json object is " + json.toString() );
return json;
}
log.error("Custom Authentication : Rule Started");
private static MediaType JSON= MediaType.parse("application/json; charset=utf-8");
private static String SECRET_KEY = "<Secret Key>";
String token= "";
String jsonBody ="";
String access_token="";
Map bodyMap = (Map) requestEndPoint.getBody();
try {
token = generateToken();
if(!token.isEmpty() || token !=null) {
log.error("Custom Authentication : JWT Assertion generated");
jsonBody = jsonObjectCreator(token);
}
if(!jsonBody.isEmpty() || jsonBody !=null) {
bodyMap.put("jsonBody", jsonBody);
}
}catch (JoseException e) {
log.error("Custom Auth Rule : Exception occurred : " + e.toString());
} catch (NoSuchAlgorithmException e) {
log.error("Custom Auth Rule : Exception occurred : " + e.toString());
} catch (InvalidKeySpecException e) {
log.error("Custom Auth Rule : Exception occurred : " + e.toString());
} catch (IOException e) {
log.error("Custom Auth Rule : Exception occurred : " + e.toString());
}catch (JSONException e) {
log.error("Custom Auth Rule : Exception occurred : " + e.toString());
}finally {
requestEndPoint.setBody(bodyMap);
log.error("Custom Authentication : In Finally block");
return requestEndPoint;
}
]]>
</Source>
</Rule>