[Script] Disable inactive users

Hi all, I am sharing a script using Looker Python SDK to disable users based on a number of days users have not logged into Looker. Please note that the script is not supported by Looker team, so if you have questions, please post here. 

Link to run in Google Colab

import looker_sdk
from looker_sdk import models40
from looker_sdk import methods40
import os
from datetime import datetime

# Environment to log in
os.environ['LOOKERSDK_BASE_URL'] = 'foo'
os.environ['LOOKERSDK_CLIENT_ID'] = 'foo'
os.environ['LOOKERSDK_CLIENT_SECRET'] = 'foo'

#Initialize the SDK
sdk = looker_sdk.init40() # or init40() for v4.0 API
print(sdk.me()["first_name"] + " has logged in")

# Main function

def deactivate(auth_method, days):
'''Deactivate unengaged users who have not logged into a Looker instance in the past amount of days.

Args:
auth_method (str): Possible input are 'email', 'embed', 'google' (Google OAuth), 'ldap', 'looker_openid', saml', 'oidc', 'totp'
days(int): Number of days since last attempted UI login
'''

'''The all_users() method returns all users in a Looker instance. To use search patterns, use search_users(), or search_users_names()'''

users = sdk.all_users()

'''In Looker UI, a non-embed user usually has one primary authentication method (usually email or SSO). In calling API/SDK call, all authentication methods will be returned, with non-active authentication returned as an empty dictionary'''
auth = "credentials_" + auth_method

'''A user with a valid authentication method but never logged in has the value for "logged_in_at" as an empty string.'''
users_with_login_date = list(filter(lambda user:user[auth] is not None and user[auth]["logged_in_at"] != "", users))

if len(users_with_login_date) == 0:
return ("No users are using the provided authentication method")

else:
user_deactivated_count = 0
user_skip_count = 0
for user in users_with_login_date:
last_login_date_str = user[auth]["logged_in_at"][0:10]
last_login_date = datetime.strptime(last_login_date_str,'%Y-%m-%d')
days_since_last_login = abs(datetime.now() - last_login_date).days
if days_since_last_login > days:
sdk.update_user(user_id = user["id"],body=models40.WriteUser(is_disabled = False))
user_deactivated_count += 1
print("Disabled user id {user_id}, {email}, whose last login date is {date}".format(user_id = user["id"], email=user[auth]["email"],date=last_login_date_str))
else:
user_skip_count += 1
print("Skipped user ID {user_id}, {email}, whose last attempted login is {date}".format(user_id = user["id"],email=user[auth]["email"], date=last_login_date_str))

print("Deactivated {user_deactivated_count}users".format(user_deactivated_count=user_deactivated_count))
4 6 2,844
6 REPLIES 6

IanT
Participant V

We use saml and I think the last auth date is when they have to authenticate which can sometimes be weeks maybe month(s) apart with usage between. We use last query date as what do you do in looker if not running a query!?

That’s a great point @IanT, thank you! “last query date” is a great a metric for inactivity.

I write this script as an example so that it could be easily adjusted for other cases. (i.e. a customer asked how we can grant “3-month temporary access” to users, and I think the same logic can be used in a custom script `if now() - users.create_day > 180 then disable`)

This script is super cool! @IanT how do you get `last_query_date`? Is that possible via the API directly or are you running a system activity Look with the API? Thanks!

IanT
Participant V

System activity

@IanT  @lantrann  What if the user has not logged in for X number of days but there is an active schedule for that user that runs at a scheduled interval? Ideally we that user should not be disabled until that schedule has been moved to a different user.  How do we capture that ?

Hello @lantrann : I am completely new to it. Would be very appreciative if you can clarify below points. 

1) Since we are using On premise Looker . Can this code be applied to the on-premise installed Looker Instance.?

2) Do i have to run this code on the machine where Looker has been hosted ?

3) From the code i saw the below information is required . Do i need all the three mentioned which is BASE URL, CLIENTID AND CLIENTSECRETKEY . From where can i get this information ?

os.environ['LOOKERSDK_BASE_URL'] = 'foo'

os.environ['LOOKERSDK_CLIENT_ID'] = 'foo'

os.environ['LOOKERSDK_CLIENT_SECRET'] = 'bar' 

4)  Since we are using Looker in On Premise, can i still execute the above code in Google Colab ?

Regards,

Lokender