The purpose of the GAM Events subscription is to allow the automatic triggering of additional (external) code when a GAM event is executed. That is, being able to execute a custom event automatically after a GAM event is executed (i.e. the creation of a GAM user).
Consider a scenario where you have a Users table, and the user information is redundant with the GAM Users table. You need to keep the Users table up to date, that is, any time a GAM User is updated (created or removed) the Users table should be updated accordingly.
The following pseudo-code would be used in that case:
&GAMUser.Save()
//Call a Procedure to make the necessary changes in the Users table.
To avoid considering this piece of code everywhere you update a GAM User, the code may be automatically triggered immediately after the GAM user is updated.
So the GAM User insert, update, and delete are considered events that automatically trigger the piece of code declared to be executed.
In other words, you subscribe to some events, so that (external) code can be triggered when any of these events is executed.
- Application_CheckPermissionFail: This event is triggered when the user is checked for permission to access the object and does not have access.
- User_Insert: Insert of a GAM User
- User_Update: Update of a GAM User
- User_Delete: Delete of a GAM User
- User_UpdateRoles: Change of roles of a list of users
- User_GetCustomInfo: This event allows customizing the information that the Identity Provider sends to the Client, and it’s executed when the Users authenticate (SSO Web) or request a token (OAuth 2.0). For this purpose, the Output of the Procedure must return a JSON. It’s recommended to use an SDT that has the structure of the information to be shared.
- User_SaveCustomInfo: This event is executed on the client when the GAM Remote or Remote Rest Authentication type (OAuth 2.0) login is successfully finished.
- Role_Insert: Insert of a role
- Role_Update: Update of a role
- Role_Delete: Delete of a role
- Repository_Login: GAM User login (any Authentication Types is supported)
- Repository_LoginFailed: User login fails (GAM Error 11 or GAM Error 18)
- Repository_Logout: GAM log out
- Repository_RememberAuthentication: This event is triggered when the user's session doesn't exist or the token has expired, and only when the user was authenticated using 'Keep me logged in'.
- User_OneTimePasswordValidUser. Check that the user who asked for an OTP code is allowed to do it.
- User_OneTimePasswordGenerateCode. Developer event to generate the OTP code.
- User_OneTimePasswordSendCode. Developer event to send the OTP code.
- User_OneTimePasswordValidateCode. Developer event to validate the OTP code.
To subscribe to an event, configure a program that will be triggered when the event is executed. The configuration may be done using the GAM API(1) or the Web Backoffice(2). This topic is discussed in more detail below.
The program that considers the GAM events, which may or may not be developed using GeneXus, has to fulfill some requirements.
First, the signature of the program has to be as follows:
(in Character &EventName, in Character &jsonIn, out Character &jsonOut)
Where:
- &EventName: belongs to the GAMEvents Domain.
- &jsonIN: JSON string whose format depends on the GAM event that the program is subscribed to (see the table below for more details).
- &jsonOUT: JSON string used to print information in the GAM trace (if it's enabled).
The Main program property has to be set to True.
Secondly, consider how the &jsonIN format should be:
Event |
GAM object received parameters |
User_Insert |
GAMUser (i.e., the jsonIN format is derived from the GAMUser object) |
User_Update |
GAMUser |
User_Delete |
GAMUser |
User_UpdateRoles |
GAMGUID collection representing the list of users whose roles were changed. |
User_GetCustomInfo |
GAMSession |
User_SaveCustomInfo |
(free format) |
Role_Insert |
GAMRole (i.e., the jsonIN format is derived from the GAMRole object) |
Role_Update |
GAMRole |
Role_Delete |
GAMRole |
Repository_Login |
GAMSession (i.e., the jsonIN format is derived from the GAMSession object) |
Repository_Logout |
GAMSession |
Repository_LoginFailed |
GAMSession |
Application_CheckPermissionFail |
GAMSessionLogCheckPermissionFail |
User_OneTimePasswordValidUser |
GAMOTPEventSubscription |
User_OneTimePasswordGenerateCode |
GAMOTPEventSubscription |
User_OneTimePasswordSendCode |
GAMOTPEventSubscription |
User_OneTimePasswordValidateCode |
GAMOTPEventSubscription |
In the following example, a subscription to the User_Insert event is used.
In the Web Backoffice(2), go through Settings > Event Subscriptions and define the Event as shown in the following figure.
Java configuration (in this example Java Package Name=com.gameventssubscription)
Status |
It may be {subscribed,unsubscribed}. It has to be subscribed for the procedure to be triggered when the event is executed. |
Event |
It's a combo box where you can select any of the events available.
|
File Name |
The name of the .dll or .class file which listens to the event execution. |
Class Name |
The name of the program including its package. |
Method Name |
The method of the program in GeneXus is always "execute". |
The code of the notifyuserinsert procedure is as follows:
Rules: Parm(in:&EventName, in:&jsonIN, out:&jsonOUT);
&GAMUser.FromJsonString(&jsonIN)
&MyUser.Load(&GAMUser.GUID) //&Myuser is based on a BC.
If &MyUser.Fail()
&MyUser = new()
Endif
&MyUser.MyUserGUID =&GAMUser.GUID
&MyUser.MyUserEmail = &GAMUser.EMail
&MyUser.MyUserName = &GAMUser.FirstName.Trim() +" "+ &GAMUser.LastName.Trim()
&MyUser.Save()
If &MyUser.Success()
//Ok
Else
//load &jsonOUT parameter with information about the error.
Endif
Sample II
See HowTo: Get user's additional information from the GAM Identity Provider for an example of User_GetCustomInfo and User_SaveCustomInfo events.
In the case of the login event, the Procedure subscribed will be triggered at login (regardless of whether the login is local or not).
In that Procedure, you can make additional controls that allow you to cancel the login and prevent a session from being generated.
Consider the following example code that triggers at login:
&GAMSession.FromJsonString(&JsonIN)
For each
Where CustomerGUID = &GAMSession.User.GUID
Where CustomerActiveSubscription = True
//OK
When none
&GAMError.Code = GAMErrorMessages.UserInactive
&GAMError.Message = "The user's subscription is not valid."
&JsonOUT = &GAMError.ToJsonString()
Endfor
The JsonOut format must be GAMError. It doesn't cancel the login unless it is empty.
What happens internally is that the session is created and revoked immediately.
You can define the event subscription as shown in the following example:
&GAMEventSubscription = new() // &GAMEventSubscription is GAMEventSubscription data type
&GAMEventSubscription.Description = "Inspecting the User Login"
&GAMEventSubscription.Event = GAMEvents.Repository_Login
&GAMEventSubscription.FileName = "aNotifyUserLogin.dll"
&GAMEventSubscription.ClassName = "GeneXus.Programs.anotifyuserlogin"
&GAMEventSubscription.MethodName = "execute"
&GAMEventSubscription.Save()
If &GAMEventSubscription.Success()
Commit
// Subscription activation:
&isOK = GAMRepository.SubscribeEvent(&GAMEventSubscription.Id, &GAMErrors)
If &isOK
Commit
Endif
Endif
You may define more than one program to be triggered when the event is executed.
Note that the subscription must be activated using the SubscribeEvent method of GAMRepository.
To include the program subscribed to the event in the same LUW (Logical Unit of Work) of the event, include the Commit command after the code that triggers the event (i.e., &GAMUser.save() or &GAMRole.save()).
Otherwise, if you don't want to include the program in the same LUW, configure Execute in new LUW property = True for the program.
The Repository_Login and Repository_Logout methods execute an implicit commit, so you don't need to execute it.
It will not be in the same LUW.