Hello, everyone. In this post, we'll be discussing how to send SailPoint IdentityIQ users email reminders that their passwords will be expiring.
We're going to assume that you have email settings configured properly in your IIQ environment. You can configure by logging into an admin account, and navigating to Global Settings -> IdentityIQ Configuration -> Mail Settings. For testing purposes, you can have email write to a file.
For our purposes of our example, we wants users to receive an initial email when their password is 2 weeks out from expiring, and then a daily email during the week leading up to expiration.
So, how are we going to accomplish this? Well, turns out we only need 3 things. An email template, a rule that sends out the email, and a task to run the rule regularly. Let's go through this step by step. Feel free to use these links if you need to skip around:
#1: Create an Email Template
Log into an admin account and navigate to the IIQ debug page at:
http://<hostname>:<port>/identityiq/debug
To make this easier, we can use an existing email template as a base, so specify EmailTemplate as the object type and open one. Make sure to change the name of the EmailTemplate and delete the "id" attribute (in addition to the "created" attribute and "modified" if it exists).
If you like, you can copy and paste the following template and use that (but again, make sure to delete the "created", "modified", and "id" attributes in the "EmailTemplate" tag). Don't forget to save your new template!:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE EmailTemplate PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<EmailTemplate created="1658341209486" id="c0a81b01821c17fb81821cd6b58e00fd" modified="1658500947002" name="Password Expiry Reminder Email Template">
<Body>Hello $targetUsername. This email is to remind you that your password expires in $daysToExpiry day(s).
</Body>
<Description>
Password expiry remind email template.
</Description>
<Signature>
<Inputs>
<Argument name="targetUsername" type="string">
<Description>The target username.</Description>
</Argument>
<Argument name="daysToExpiry" type="string">
<Description>Amount of days until password expires.</Description>
</Argument>
</Inputs>
</Signature>
<Subject>Password expiry reminder for $targetUsername</Subject>
</EmailTemplate>
Let's discuss some of the parts of this template:
The "Inputs" are going to be our external arguments. We'd like our emails to be personal, so it would be nice to include the user's username, which we do so by giving the argument name "targetUsername". We also include how many days until their password expires, as this number should be different, depending on the day.
The "Subject" is the email's subject line. As you can see, we reference the username passed in as an argument by its name, "$targetUsername".
The "Body" will be the email's body. Again, we reference passed in arguments using "$targetUsername" and "$daysToExpiry".
But wait? Where are those arguments coming from? Why, from the rule that's going to be sending emails using this template, which brings us to our next section.
#2: Create the Rule that will send out emails
While we're still in the debug page, let's create our rule. Once again, we can open up an existing rule and edit there, so changed the object type to Rule and open one. Here's our rule that you can copy and paste (delete the aforementioned attributes and name it whatever you like):
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule created="1658342401562" id="c0a81b01821c143381821ce8e61a0012" language="beanshell" modified="1658522943390" name="Password Expiry Reminder Rule" type="BuildMap">
<Description>
Example rule to send email
</Description>
<Signature returnType="Map">
<Inputs>
<Argument name="context">
<Description>
A sailpoint.api.SailPointContext object
</Description>
</Argument>
<Argument name="log">
<Description>
The log object associated with the SailPointContext.
</Description>
</Argument>
</Inputs>
</Signature>
<Source>
import sailpoint.api.*;
import sailpoint.object.*;
import sailpoint.tools.*;
import java.util.*;
import java.lang.*;
import java.text.*;
import java.time.temporal.ChronoUnit;
import java.time.LocalDate;
import java.util.concurrent.TimeUnit;
import java.time.ZoneId;
LocalDate todayLocalDate = LocalDate.now();
Date todayDate = new Date();
long daysAhead14 = todayLocalDate.plusDays(14).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
long daysAhead15 = todayLocalDate.plusDays(15).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
long daysAhead8 = todayLocalDate.plusDays(8).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
long daysAhead1 = todayLocalDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
QueryOptions qo= new QueryOptions();
qo.addFilter(Filter.or(Filter.and(Filter.ge("passwordExpiration", new Date(daysAhead14)), Filter.lt("passwordExpiration", new Date(daysAhead15))), Filter.and(Filter.ge("passwordExpiration", new Date(daysAhead1)), Filter.lt("passwordExpiration", new Date(daysAhead8)))));
List<Identity> identities = context.getObjects(Identity.class, qo);
String tplName = "Password Expiry Reminder Email Template";
EmailTemplate template = context.getObjectByName(EmailTemplate.class, tplName);
if (null == template) {
log.error("ERROR: could not find email template [ " + tplName + "]");
return;
}
template = (EmailTemplate) template.deepCopy(context);
if (null == template) {
log.error("ERROR: failed to deepCopy template [ " + tplName + "]");
return;
}
Map args = new HashMap();
for (Identity identity : identities)
{
int diffInMillies = identity.getPasswordExpiration().getTime() - new Date().getTime();
int noOfDaysBetween = TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS);
String emailDest = identity.getEmail();
if (null == emailDest) {
log.error("ERROR: could not find email for user [ " + identity.getName() + "]");
continue;
}
args.put("targetUsername", identity.getName());
args.put("daysToExpiry", noOfDaysBetween);
EmailOptions ops = new EmailOptions(emailDest, args);
context.sendEmailNotification(template, ops);
}
return;
</Source>
</Rule>
It may look like much, but we'll discuss what's going on.
Since we want to email the users that fit within our criteria (password expiring in exactly 2 weeks or in less than week), we first calculate some dates that we'll use to filter users. We calculate 4 different dates, which will be our bounds: 14 days ahead, 15 days ahead, 1 day ahead, and 8 days ahead:
Next, we build our filter and use it to query our relevant users. This filter looks complicated, but it's essentially saying "Get me all the users whose passwordExpiration value is between 14(inclusive) and 15(exclusive) days ahead OR between 1(inclusive) and 8(exclusive) days ahead.
Next, we get the template that we created in step 1. Make sure the name in the code matches the name we used for the template.
Finally, for every user returned by our query, we calculate the individual days until password expiration (which will be either 14 or between 1-7), and we send them an email, passing the calculated number and their username as arguments. As you can see, the argument names match the arguments that we specified in the email template from step 1.
And that's our rule! Don't forget to save it. Running this as is should work, but we want this rule to run automatically on a set schedule, right? That brings us to our final step.
#3: Create a Scheduled Task
Navigate to Setup -> Tasks, click "New Task", and select "Run Rule". Give your new task a name and make sure to select the rule we created in step 2. Save.
Now back in the Tasks page, locate your new task, right-click it, and select "Schedule". Fill in necessary details, and change the execution frequency to "Daily". Then simply hit "Schedule".
And that's all there is to it! We hope that this guide proves useful to you!
- Gil
Comentarios