Live Report: Show Custom Attributes Across Applications

Version

8.4

Screenshots

Question

Hi everyone :waving_hand:,

I’m working on a custom Live Report in SailPoint IdentityIQ to display accounts grouped by applications. Right now, my report shows basic fields like identity.name, identity.displayName, and account.displayName.

Problem

I want to add more account-level attributes to the report — for example, a field like accountCreated (which should reflect the account creation date). But I’m having trouble figuring out how to display custom account attributes in the LiveReport XML.

Additionally, the attribute names vary across applications:

  • Some apps use accountCreated
  • Others use createdAt
  • And some just use created

Question

  1. How can I reference these custom attributes from the account (Link object) in my Live Report XML?
  2. What’s the best way to handle the inconsistency of attribute names across different applications?

Here’s a snippet of my current XML for reference:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE TaskDefinition PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<TaskDefinition created="1745466789945" executor="sailpoint.reporting.LiveReportExecutor" id="7f00010196651d11819665ed90380008" name="Users by Application Report" progressMode="Percentage" resultAction="Rename" subType="Identity and User Reports" template="true" type="LiveReport">
  <Attributes>
    <Map>
      <entry key="report">
        <value>
          <LiveReport title="Users by Application Report">
            <DataSource objectType="Link" type="Filter">
              <QueryParameters>
                <Parameter argument="applications" property="application.id"/>
              </QueryParameters>
            </DataSource>
            <Columns>
              <ReportColumnConfig field="application" header="rept_users_by_app_col_app" property="application.name" sortable="true" width="110"/>
              <ReportColumnConfig field="identityDisplayName" header="rept_users_by_app_col_identity_display" property="identity.displayName" sortable="true" width="110"/>
              <ReportColumnConfig field="identityName" header="rept_users_by_app_col_identity" property="identity.name" sortable="true" width="110"/>
              <ReportColumnConfig field="account" header="rept_users_by_app_col_account_id" property="nativeIdentity" sortable="true" width="110"/>
              <ReportColumnConfig field="accountDisplayName" header="rept_users_by_app_col_account_name" property="displayName" sortable="true" width="110"/>
            </Columns>
          </LiveReport>
        </value>
      </entry>
    </Map>
  </Attributes>
  <Description>A detailed view of the users in the system categorized by the applications that they belong to.</Description>
  <RequiredRights>
    <Reference class="sailpoint.object.SPRight" id="7f00010196161e778196165ef5c6004a" name="FullAccessApplicationUserReport"/>
  </RequiredRights>
  <Signature>
    <Inputs>
      <Argument multi="true" name="applications" type="Application">
        <Description>rept_input_app_user_report_apps</Description>
      </Argument>
    </Inputs>
  </Signature>
</TaskDefinition>

I’d really appreciate it if anyone could:

  • Suggest how to include a custom attribute like accountCreated in the <ReportColumnConfig>
  • Share an example of how you’ve handled different attribute names across applications in a Live Report

Thanks in advance for your help! :folded_hands:

Hi,

If it is safe to assume that the account creation date and the link creation date on the identity for that application are same, you can directly use link.created property to pull that information. If not, you can use the render script within the reportcolumnconfig to write the code and pull the required data. Please refer to the reports guide of Sailpoint IIQ for more information.

Example:

<ReportColumnConfig field="status" header="rept_remediation_progress_grid_col_status" property="
action.remediationCompleted" sortable="true" width="110">
<RenderScript>
<Source>
import sailpoint.tools.Message;
import sailpoint.web.messages.MessageKeys;
return value == true ? Message.localize(MessageKeys.WORK_ITEM_STATE_FINISHED) : Message.
localize(MessageKeys.WORK_ITEM_STATE_OPEN);
</Source>
</RenderScript>
</ReportColumnConfig>

You can also use a rule to do this:

<ReportColumnConfig field="status" header="rept_remediation_progress_grid_col_status" property="
action.remediationCompleted" sortable="true" width="110">
<RenderRule>
<Reference class="sailpoint.object.Rule" id="4028460238ed9b8e0138ed9bf61300de" namee="
Status Message RenderRule"/>
</RenderRule>
</ReportColumnConfig>

Only option which i can think of is you need to create some link entended attribute lets say created and then you need to populate createAt , createOn etc field of differnet application to the extended attribute create and then can be shown in the report .

I tried to link but I got the error from this code, can you help me check something wrong on my code?

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE TaskDefinition PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<TaskDefinition created="1699519558357" executor="sailpoint.reporting.LiveReportExecutor" id="6448864b8bb31226818bb34272d4021c" modified="1712228858726" name="Fetch Users by Application Report" progressMode="Percentage" resultAction="Rename" subType="Identity and User Reports" template="true" type="LiveReport">
  <Attributes>
    <Map>
      <entry key="report">
        <value>
          <LiveReport title="Fetch Users by Application Report">
            <DataSource objectType="Link" type="Filter">
              <QueryParameters>
				<Parameter argument="identity" property="identity.id"/>
                <Parameter argument="applications" property="application.id"/>
              </QueryParameters>
            </DataSource>
            <Columns>
              <ReportColumnConfig field="application" header="rept_users_by_app_col_app" property="application.name" sortable="true" width="80"/>
              <ReportColumnConfig field="identityDisplayName" header="rept_users_by_app_col_identity_display" property="identity.displayName" sortable="true" width="110"/>
              <ReportColumnConfig field="identityName" header="rept_users_by_app_col_identity" property="identity.name" sortable="true" width="80"/>
              <ReportColumnConfig field="account" header="rept_users_by_app_col_account_id" property="nativeIdentity" sortable="true" width="80"/>
              <ReportColumnConfig field="accountDisplayName" header="rept_users_by_app_col_account_name" property="displayName" sortable="true" width="80"/>
			  <ReportColumnConfig field="accountStatus" header="Account is Inactive" property="identity" scriptArguments="application, nativeIdentity" skipLocalization="true" width="100">
                <RenderScript>
                  <Source>
                    import sailpoint.object.Link;
                    import sailpoint.object.Application;
                    import java.util.List;


                    Application application = (Application) scriptArgs.get("application");
                    String nativeId = (String) scriptArgs.get("nativeIdentity");

                    List links = value.getLinks();
                    if (links != null) {
                    for (Link link : links) {
                    if (link.getApplication().equals(application) &amp;&amp; link.getNativeIdentity().equals(nativeId)) {
                    return link.isDisabled();
                    }
                    }
                    }
                    return false;

                  </Source>
                </RenderScript>
              </ReportColumnConfig>
            </Columns>
          </LiveReport>
        </value>
      </entry>
    </Map>
  </Attributes>
  <Description>A detailed view of the users in the system categorized by the applications that they belong to.</Description>
  <RequiredRights>
    <Reference class="sailpoint.object.SPRight" id="6448864b8bb31226818bb3423f9d0061" name="FullAccessApplicationUserReport"/>
  </RequiredRights>
  <Signature>
    <Inputs>
	  <Argument multi="true" name="identity" type="Identity">
        <Description>Identities to include in the report</Description>
        <Prompt>identities</Prompt>
      </Argument>
      <Argument multi="true" name="applications" type="Application">
        <Description>rept_input_app_user_report_apps</Description>
      </Argument>
	   <Argument name="accountId">
        <Description>Account ids to include in the report</Description>
        <Prompt>account_name</Prompt>
      </Argument>
    </Inputs>
  </Signature>
</TaskDefinition>

I got more information, it’s seem like the xml code will show the attribute value from <Link xx=“xyz”.>, do you know how can i access the attribute? to show the attribute inside the tag like <entry key="region" value="Benin"/> in the Identity example xml?

This is the Identity xml in debug

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Identity PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Identity correlated="true" created="1744133451068" id="7f0001019616110f819616746d3b0052" lastRefresh="1744133451101" modified="1745476855266" name="Bernice Wisoky" needsRefresh="true" significantModified="1745476855236">
  <Attributes>
    <Map>
      <entry key="displayName" value="Bernice Wisoky"/>
      <entry key="email" value="[email protected]"/>
      <entry key="firstname" value="Bernice"/>
      <entry key="lastname" value="Wisoky"/>
    </Map>
  </Attributes>
  <AttributeMetaDatas>
    <AttributeMetaData attribute="firstname" source="HR Employee:firstName"/>
    <AttributeMetaData attribute="lastname" source="HR Employee:lastName"/>
    <AttributeMetaData attribute="email" source="HR Employee:email"/>
    <AttributeMetaData attribute="displayName" source="HR Employee:fullName"/>
  </AttributeMetaDatas>
  <Workgroups>
    <Reference class="sailpoint.object.Identity" id="7f00010196651e8181966687259100cf" name="Employee"/>
  </Workgroups>
  <Links>
    <Link created="1744133451069" displayName="Bernice Wisoky" id="7f0001019616110f819616746d3d0053" lastRefresh="1744133451069" modified="1744133451070" identity="EMP1009" significantModified="1744133451070">
      <ApplicationRef>
        <Reference class="sailpoint.object.Application" id="7f0001019616110f81961662c5f3000b" name="HR Employee"/>
      </ApplicationRef>
      <Attributes>
        <Map>
          <entry key="costcenter" value="CC-608"/>
          <entry key="department" value="Clothing"/>
          <entry key="email" value="[email protected]"/>
          <entry key="employeeId" value="EMP1009"/>
          <entry key="firstName" value="Bernice"/>
          <entry key="fullName" value="Bernice Wisoky"/>
          <entry key="inactiveUser" value="true"/>
          <entry key="jobtitle" value="Central Mobility Associate"/>
          <entry key="lastName" value="Wisoky"/>
          <entry key="location" value="South Gregorio"/>
          <entry key="region" value="Benin"/>
          <entry key="workStatus" value="Inactive"/>
        </Map>
      </Attributes>
    </Link>
  </Links>
</Identity>

A good way to handle inconsistent attribute names across applications is by defining an extended attribute in the Link object using ObjectConfig, and referencing that in your report via ReportColumnConfig. This provides a unified view and makes reporting more consistent.

Sample ObjectAttribute definition to standardize an attribute like accountCreatedDate from different applications:

<ObjectAttribute displayName="accountCreatedDate" editMode="ReadOnly" extendedNumber="2" name="accountCreatedDate" type="string">
    <AttributeSource name="created">
      <ApplicationRef>
        <Reference class="sailpoint.object.Application" id="7f00000190431db2819075ff3b0d2a8e" name="Okta"/>
      </ApplicationRef>
    </AttributeSource>
    <AttributeSource name="created">
      <ApplicationRef>
        <Reference class="sailpoint.object.Application" id="c0a8014d959316d08195933fb7a50025" name="Okta SaaS"/>
      </ApplicationRef>
    </AttributeSource>
  </ObjectAttribute>

If you’re using multiple ReportColumnConfig definitions and want to simplify the setup, you can also use an ExtendedColumnScript. This keeps your code cleaner and makes it easier to maintain. Add the following block after your DataSource section in the report definition:

Sample script:

<ExtendedColumnScript>
  <Source><![CDATA[  
                              
                import sailpoint.object.Policy;
                import sailpoint.object.ReportColumnConfig;
                import sailpoint.object.Script;
  
                List<String> colNames = Arrays.asList("name");
               
                List newCols = new ArrayList();
                for(String colName : colNames)
                {
                  ReportColumnConfig newCol = new ReportColumnConfig(colName, "id");
                  newCol.setHeader(colName);
                  newCol.setSortable(true);
                  newCol.setHidden(false);
                  newCol.setRenderScript(
                    new Script(
                      "import sailpoint.object.Policy;" +
                      "import sailpoint.object.Identity;" +
                      "Policy policy = context.getObjectById(Policy.class,value);" +
                      "return policy.getName();"
                    )
                  );

                  newCols.add(newCol);
                }

                return newCols;       
                                 
           ]]></Source>
</ExtendedColumnScript>

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.