Grails Audit Logging: Selective auditing and onChange method - grails

We are using grails audit logging plugin for auditing few domain objects in our project
https://grails.org/plugin/audit-logging
Facing couple of issues related to it:
We have a user domain object which we want to audit.
We also create lot of users during our system set up. So, when we make auditable = true for User domain, it audits that as well - creates a new row in audit_log_event table for each user that gets created.
Is there a way to avoid this? We just want to audit when a user is created/updated by an admin user (basically when the admin user is logged in)
For some of the attributes of a domain object that we are auditing, we want to make some modification in the new value.
Example: Lets say email address of User object is getting updated from a#gmail.com to b#gmail.com, then we want to insert "***B#gmail.com-12:23:47" in new_value column of audit_log_event table.
I thought by updating the value of newMap[key] in onChange() method, we can do this, but that doesn't seem to work.
Is there a way to do this?
Tried this:
def onChange = {
oldMap,newMap ->
println "User was changed ..."
oldMap.each({ key, oldVal ->
if(oldVal != newMap[key]) {
println " * $key changed from $oldVal to " + newMap[key]
if(key == "email") {
newMap[key] = "*****Some value udpated****"
println "email is now again changed ..."
println " * $key changed from $oldVal to " + newMap[key]
}
}
})
}
Console output:
User was changed ...
* email changed from a#gmail.com to b#gmail.com
email is now again changed ...
* email changed from a#gmail.com to *****Some value udpated****
However, in DB:
old_value = a#gmail.com
new_value = b#gmail.com

Related

Grails: Audit plugin: dateCreated has different value than stored in database

I have used "org.grails.plugins:audit-logging:3.0.5" plugin. There's a table named User and I have to take its exact dateCreated value (automatically populated from plugin) and send it into SQS message. However different value in seconds is sent. Here's my code:
User user = new User()
user.status = "something"
def newUser = user.save(failOnError: true, flush: true)
msgBody.timeStamp = newUser.dateCreated
If there's 2020-09-14 20:44:58 dateCreated in database, 2020-09-14 20:44:57 is being sent in msgBody. Please help.
msgBody is an object sent from frontend(angularjs) to backend as JSON.

Retrieve jenkins job builder credentials in groovy

I am trying to extract the username and password in jenkins groovy script who has initiated the build. I need these details to post comments on jira from my name.
So for eg.. I login into jenkins and start a job, then my login credentials should be used to post the comment on jira..
I tried alot of posts but didnt find anytihng related to my requirement.
Any help will be appreciated..
after few seconds of Googling, I found this script officially published by cloudbees.
So, as follows:
Jenkins.instance.getAllItems(Job).each{
def jobBuilds=it.getBuilds()
//for each of such jobs we can get all the builds (or you can limit the number at your convenience)
jobBuilds.each { build ->
def runningSince = groovy.time.TimeCategory.minus( new Date(), build.getTime() )
def currentStatus = build.buildStatusSummary.message
def cause = build.getCauses()[0] //we keep the first cause
//This is a simple case where we want to get information on the cause if the build was
//triggered by an user
def user = cause instanceof Cause.UserIdCause? cause.getUserId():""
//This is an easy way to show the information on screen but can be changed at convenience
println "Build: ${build} | Since: ${runningSince} | Status: ${currentStatus} | Cause: ${cause} | User: ${user}"
// You can get all the information available for build parameters.
def parameters = build.getAction(ParametersAction)?.parameters
parameters.each {
println "Type: ${it.class} Name: ${it.name}, Value: ${it.dump()}"
}
}
}
You will get the user ID of the user, which start the job, for sure you will not be able to get his credentials, at least not in the plain text.
Little explanation
//to get all jobs
Jenkins.instance.getAllItems(Job)
{...}
//get builds per job
def jobBuilds=it.getBuilds()
//get build cause
def cause = build.getCauses()[0] //we keep the first cause
//if triggered by an user get id, otherwise empty string
def user = cause instanceof Cause.UserIdCause? cause.getUserId():""

How to get a List of Objects that a user can access using ACLs related tables

I'm designing a system that has a lot of requirements around user management/permissions, so I decided to use Spring Security ACL to manage the permissions at the Domain Objects level.
Although, using ACLs to maintain the relations between Users and Entities force us to rely on that to present the data on the UI.
The PostFilter solution that is provided by Spring Security does a good job filtering the objects that a User can/cannot see but it has a big performance issue when we're dealing with an entity that has hundreds/thousands of entries, because we need to load everything from the database and then discard the objects that user isn't allowed to "see".
That problem is described here - SEC-2409 - but it'll take some time until the feature is available. So, I'm trying to find a workaround to use Spring Security ACL but avoid the performance issue.
I thought about implementing some code to retrieve the Objects that a User can access (after the authentication process) and keep that information available to be used on every request to allow the developers to use that info to perform the queries and not relying on the PostFilter.
In order to implement that, I'm trying to find a way to retrieve the list of permissions for a given principal/granted authority but I'm not able to find a way to do that with the available AclService implementations.
Example: aclService.getObjectIdentityList(<sid>,<acl_class>)
Note: The method should use the inheritance structure and include all the ObjectIdentities that are inherited from a parent entry
Any suggestion to get the data or another approach to solve this problem?
UPDATE
I already found a way to retrieve the List of objects that a User can access.
List<ObjectIdentity> childObjects = aclService.findChildren(objectIdentity);
Map<ObjectIdentity, Acl> result = aclService.readAclsById(childObjects, sids);
And this approach work for us, because we just have a few entities which the access is controlled by ACLs, so we can construct the list of ObjectsIdentities that a User has access.
Although, the Map that is being return, is returning all the ACLs for the ObjectIdentities that are being passed and then I need to check the if the user has access to each ObjectIdentity that is being returned.
Do you have an easy way to do this or to simplify all of this logic?
The current approach to handling larger data sets is to update your query to include the currently logged in user within your query. For example, you can use Spring Security and Spring Data integration to update your query to refer to the current user:
#Query("select d from MyDomain d where d.owner = #{principal.name}")
Obviously this is not ideal because you need to manage the permissions manually. Once we resolve SEC-2409 Spring can do a lot of the heavy lifting for you automatically.
I ran into this question from needing a solution to deal with the lack of SEC-2409. Looking at JdbcAclService.findChildren() lead me to this
private final String FIND_OBJECTS_WITH_ACCESS = ""+
"SELECT " +
" obj.object_id_identity AS obj_id, " +
" class.class AS class " +
"FROM " +
" acl_object_identity obj, " +
" acl_class class, " +
" acl_entry entry " +
"WHERE " +
" obj.object_id_class = class.id " +
" and entry.granting = true " +
" and entry.acl_object_identity = obj.id " +
" and entry.sid = (SELECT id FROM acl_sid WHERE sid = ?) " +
" and obj.object_id_class = (SELECT id FROM acl_class WHERE acl_class.class = ?) " +
"GROUP BY " +
" obj.object_id_identity, " +
" class.class ";
public List<ObjectIdentity> getObjectsWithAccess(Class clazz, String sid) {
Object[] args = { sid, clazz.getName() };
List<ObjectIdentity> objects = _jdbcTemplate.query(FIND_OBJECTS_WITH_ACCESS, args, getRowMapper());
return objects.size() == 0 ? null : objects;
}
private RowMapper<ObjectIdentity> getRowMapper() {
return (rs, rowNum) -> {
String javaType = rs.getString("class");
Long identifier = rs.getLong("obj_id");
return new ObjectIdentityImpl(javaType, identifier);
};
}

How to switch the user tenant id in Grails Multi Tenant Single DB plugin without relogin

Use Case : A single user with “single user name” should be able to use data available in different tenant without relogin.
Expected Flow :
User “A” login into tenant 1
He done some activity and able to access all tenant 1 data
He clicks on the “switch tenant” link and after that he should be able to access all data related to Tenant 2
Environment :
Grails v2.1
spring-security-core v1.2.7.3
multi-tenant-single-db v0.8.3
I am using following auto generated class
SpringSecurityTenantRepository
SpringSecurityTenantResolver
I used following code in controller but it did not work.
def switchedTenentId = params.switchedTenentId
if(switchedTenentId != null && !"".equals(switchedTenentId))
{
def currUser = springSecurityService.currentUser
springSecurityService.currentUser.userTenantId = new Long(switchedTenentId)
}
I googled but did not find any solution. I like to know the logic, solution or any sample code.
Thanks
Here is what I did:
User u = User.get(springSecurityService.currentUser.id)
u.userTenantId = params.switchedTenentId.toInteger()
u.save flush: true
springSecurityService.reauthenticate u.username
It worked like a charm.

Send an email when a new record is created via admin generator

I had used the symfony admin generator to create an web application for athletes management. One of the last client's requirement was to add a feature to notice the user and send an e-mail to the administrators when an athlete with the same number is inserted on the database. Until now, the column number of the Athlete table had a unique constraint but the client desires that the athlete can by inserted anyway.
To accomplish that, I was trying to extend the the edit / new actions in order to implement the client requirements.
Here is the code:
public function executeEdit(sfWebRequest $request)
{
$user = $this->getUser();
if(! $user->hasCredential('admin'))
{
$clube_id = $user->getAttribute('id');
$atleta_id = $request->getParameter('id');
$atleta = Doctrine::getTable('Atleta')->find($atleta_id);
if($clube_id != $atleta->clube_id)
$this->forward404();
}
if($request->get('post'))
{
// check if the inserted athlete BI already exists; if so, display a message to the user and send an email to the system admins
$atleta_id = $request->getParameter('id');
$atletaBIExiste = Doctrine::getTable('Atleta')->findDuplicateAthleteBI($atleta_id);
if($atletaBIExiste)
{
// display a notice message to the user
$this->getUser()->setFlash('error', 'Athlete already exists');
// send an email to the system administrator
}
}
return parent::executeEdit($request);
}
Here is my problem: when I execute the edit action, I only want to check for a duplicate athlete number when the HTTP is POST but it seems that never is. I had already sent some exceptions to the output to verify which type is HTTP Request and it seems it is always GET.
The problem you will be having is that when you hit save on the Edit page the information isn't posted to the edit action, it is posted to an action called update.
Have a look at the actions.class.php file in the cache and you will see it.

Resources