(login) History for all

Login History without Manage Users permissions

Recently someone asked me how to expose the login history without giving the individual users the manage users permission. The goal was to allow the internal support team to view the login history of portal users. Off the top of my head, I thought this would be the perfect use case for illustrating the power of the ‘without sharing’ Apex keywords. So after a few minutes we had built an Apex controller and Visualforce page we thought would work. Initial testing, as System Administrator users was promising. Loading the Visualforce page showed us the last 25 login history records for the User we specified. Unfortunately, loading that same page as a support user yielded 25 blank lines!

All was not lost, however, as we refactored the controller more in line with best practices. Moving our login history data to a wrapper class allowed the data to be visible to users who had permission to access the controller and page! Here’s the final product:

2015-09-30 at 10.06 PM

 

 

And here’s the code:

public without sharing class UserLoginHistory{
public class loginHistoryWrapper {
public DateTime LoginTime {get;set;}
public String Status {get;set;}
public String LoginURL {get;set;}
public String LoginType {get;set;}
public String Application {get;set;}
public String Browser {get;set;}
public ID UserId {get;set;}
public loginHistoryWrapper(DateTime lt, String statuss, String LR, String ltype, String app, String brow, ID uid){
LoginTime = lt;
Status = statuss;
LoginURL = LR;
LoginType = ltype;
Application = app;
Browser = brow;
UserId = uid;
}
}
private Map<String, String> UrlParameterMap;
private User pU {get; set;}
public User u {
get{
if(pU == null){
pU = [SELECT name FROM User WHERE ID = :UrlParameterMap.get('userId')];
}
return pU;
}
}
public List<LoginHistoryWrapper> Records {get; set;}
public UserLoginHistory(){
UrlParameterMap = ApexPages.currentPage().getParameters();
List<LoginHistory> lRecords = [
SELECT LoginTime, Status, LoginURL, LoginType, Application, Browser, UserId
FROM LoginHistory
WHERE UserId= :UrlParameterMap.get('userId')
ORDER BY LoginTime DESC LIMIT 25];
Records = new List<LoginHistoryWrapper>();
For(LoginHistory lh : lRecords){
Records.add(new LoginHistoryWrapper(lh.loginTime, lh.status, lh.loginURL, lh.LoginType, lh.Application, lh.Browser, lh.UserId));
}
}
}

view raw
LoginHistoryCtrl.cls
hosted with ❤ by GitHub

The secret sauce here is our wrapper object. Converting the loginHistory objects to our wrapper object allows the data to be seen by users without the Manage Users Permission.

<apex:page controller="UserLoginHistory">
<apex:pageBlock title="Login History for {!u.Name}">
<apex:pageBlockTable value="{!Records}" var="Record">
<apex:column >
<apex:facet name="header">User's Name</apex:facet>
<apex:outputText value=" {!u.name}"/>
</apex:column>
<apex:column >
<apex:facet name="header">Login Time</apex:facet>
<apex:outputText value=" {!Record.LoginTime}"/>
</apex:column>
<apex:column >
<apex:facet name="header">Status</apex:facet>
<apex:outputText value="{!Record.Status}"/>
</apex:column>
<apex:column >
<apex:facet name="header">Login Type</apex:facet>
<apex:outputText value="{!Record.LoginType}"/>
</apex:column>
<apex:column >
<apex:facet name="header">Client Type</apex:facet>
<apex:outputText value="{!Record.Application}"/>
</apex:column>
<apex:column >
<apex:facet name="header">Browser</apex:facet>
<apex:outputText value="{!Record.Browser}"/>
</apex:column>
<apex:column >
<apex:facet name="header">Login URL</apex:facet>
<apex:outputText value="{!Record.LoginURL}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>

view raw
LoginHistoryPage.vfp
hosted with ❤ by GitHub

Viola! a safe way to expose login history with internal users without giving them ManageUsers permission!

Leave a Reply

Your email address will not be published. Required fields are marked *