I want to create a Role for each User Group within my portal so that I can grant specific access to many users at once, depending on what groups they belong to.
Using Liferay API, is there any way to programmatically add a Role for each User Group that exists within the Portal?
This would be more efficient than adding each role individually through the UI.
Something like
for(i = 0; i < userGroups.size(); i++){
roles.add(userGroups[i].getName());
}
If possible, I'd like to then assign the same User Group to that Role within the same method, otherwise the role would know nothing of the associated user group:
roles.assignUserGroup(userGroups[i]);
Anyone accomplished a task similar to this?
Linked Liferay Forum Post http://liferay.com/community/forums/-/message_boards/message/46355079
In short you need to create a Role with a similar name as that of the UserGroups you have and then assign the UserGroup to that Role.
You can do that programmatically with Liferay's API, since that is how liferay also creates the different types of Roles and assigns users, user-groups etc to the role.
You just need to dig into to the source code to do this. Check source code for RoleLocalServiceImpl, UserGroupLocalServiceImpl and GroupLocalServiceImpl.
I am providing the steps for Liferay v6.2, there should not be much change in 6.0 and 6.1:
Fetch all the UserGroups using UserGroupLocalServiceUtil.getUserGroups(companyId)
Loop through it as you have done:
for (UserGroup userGroup : userGroups) {
... // steps to follow
}
Get the name of the UserGroup: userGroup.getName()
Create a Role using RoleLocalServiceUtil.addRole( ... ) and assign the userGroup to role using GroupLocalServiceUtil.addRoleGroups( ... )
for (UserGroup userGroup : userGroups) {
String userGroupName = userGroup.getName();
// for locale specific title (optional, can be null)
Map<Locale, String> titleMap = new HashMap<Locale, String>();
titleMap.put(Locale.ENGLISH, userGroupName);
// for locale specific description (optional, can be null)
Map<Locale, String> descriptionMap = new HashMap<Locale, String>();
titleMap.put(Locale.ENGLISH, "Role created for UserGroup - " + userGroupName);
int type = RoleConstants.TYPE_REGULAR;
// adding the role
Role role = RoleLocalServiceUtil.addRole(userId, Role.class.getName(), 0, userGroupName, titleMap, descriptionMap, type, null, null);
// assigning the UserGroup to the role
GroupLocalServiceUtil.addRoleGroups(role.getRoleId(), new long[]{userGroup.getGroupId()}); // need to pass groupId and not userGroupId
}
Now were would you write this code-snippet? There are various places depending upon what requirement you have:
Custom plugin portlet with a UI to execute this code. (better if required periodically)
Custom plugin action-hook and the code goes inside a StartUpAction, executes the code when the hook is being deployed. Hook should be undeployed or else will run everytime the hook is deployed. (better for one time use)
Custom plugin upgrade hook, executes the code during deployment once based on the upgrade condition. (better for one time use)
Use Beanshell, Server Administration → Script → Select Beanshell → Paste the code-snippet → Execute. You need to have the proper import statements and then just the code-snippet and you are good to go. For an example of Beanshell usage you can check my other answer. (better for one time use)
Even after all this you would still have to take the pains to give permission to each role ;-)
Hope this helps though.
Related
We have 5 custom reports for our 94 districts. A capability grants access to these custom reports.
The issue is that each district should not see the report results from another district.
Currently, the only alternative is to create 5 * 94 = 470 custom reports, granting a set of 5 to each district. However, this is cumbersome when a report needs to be updated.
TaskDefinitions (Reports) create TaskResult objects (the result of a report). In addition, to the TaskResult object, a JasperReport object is created. Neither the TaskResult/JasperResult object "re-executes" BeanShell when you open the task result.
Is there a way to only have 5 reports and scope the results so that only users in that district can see them?
I have an example of how this might be achieved when based on this code below which will look at the scope(s) of the one who is running the report. It will only return identities that are in the same scope as the one that is running the report
// Retrieve Scope of Executor then filter all Identities on that Scope only
import org.apache.commons.logging.Log;
import sailpoint.object.Filter;
import sailpoint.object.Identity;
import sailpoint.object.Scope;
Identity identity = context.getObjectByName(Identity.class, arguments.get("launcher"));
if (identity != null) {
String scopeName = identity.getAssignedScope().getDisplayableName();
List roleFilters = new ArrayList();
if (scopeName!= null) {
roleFilters.add(Filter.eq("identity.assignedScope.name", scopeName));
}
if (!roleFilters.isEmpty()) {
queryOptions.addFilter(Filter.or(roleFilters));
}
} else {
// When Saving with Preview or Execute the Launcher is empty so all results would be shown.
// This filter will prevent that (creates empty report, it works when executed from the My Reports
queryOptions.addFilter(Filter.eq("identity.name", "xxx"));
}
return queryOptions;
The problem with the code sample above:
This will create the report intended for Group A, however Group B, and C will also be able to view it.
So the end goal is to have one report that anyone can run, however only the data that is associated with that scope is visible no matter what user group is involved (scope). So Group B would only be able to view Group B even if Group A ran it.
I think you don't have good options here.
What comes to my mind is to create these reports programatically (writing some script to generate the XML artifact for the TaskDefinition and importing/exporting using IIQDA for example) and maintain them in the same way, so everytime you need to change each one of these hundreds of artifacts, you can just re-generate them via code.
The only thing I'd do in a different way is to use 94 scopes for each 5-set report instead of using capabilities.
I'm writing a java component which build all the pages in a wiki. What would be the best way to assign the user rights or groups which may view the page or spaces from within the java service component?
Really struggling to find details on this in the API.
You are finding no details in the API, because the Rights API is only about reading rights information, not setting rights
If you want to set permissions on pages programatically, and you can assume that the default permission handler is in place (which both the UI and the code to create new users in XWiki does, so it seems not too unreasonbale), you can create them as objects in the pages.
Permissions are set by adding objects of type "XWiki.XWikiRights" to the pages
these objects have the following attributes:
groups : a string containing a comma separated list of group references (e.g. XWiki.XWikiAdminGroup,XWiki.XWikiAllGroup for the default admin and "all members" group)
users : a string containing a comma separated list of user references (e.g. xwiki:XWiki.Admin,XWiki.Admin would describe the main wiki admin and the "Admin" account in the local wiki
levels : a string containing a comma separated list of permissions who ate affected by this entry, e.g. view,comment,edit
allow : an integer which should have two values: 1 means the entry is an "allow this right", 0 means it is a "deny these rights"
The groups and users fields can be empty, though usually one of them is filled with data. The levels and allow must be set with some values.
One example how a permission is set on a page is the (internal) method XWiki.protectUserPage which sets the permissions on a newly create user in the way this user can edit ones one profile page:
public void protectUserPage(String userName, String userRights, XWikiDocument doc, XWikiContext context)
throws XWikiException
{
DocumentReference rightClassReference = getRightsClass(context).getDocumentReference();
EntityReference relativeRightClassReference =
rightClassReference.removeParent(rightClassReference.getWikiReference());
// Allow users to edit their own profiles
BaseObject newuserrightsobject = doc.newXObject(relativeRightClassReference, context);
newuserrightsobject.setLargeStringValue("users", userName);
newuserrightsobject.setStringValue("levels", userRights);
newuserrightsobject.setIntValue("allow", 1);
}
Here the first few lines are slightly more complicated to make sure the XWiki.XWikiRights class page is present and properly initialized; without harm you should be able to do something simpler like:
BaseObject newrightsobject = doc.newObject("XWiki.XWikiRights", context);
The userRights is usually edit here (it was only that while looking for the code that I found out this is actually configurable ...); userName is the full name of the users profile page here (e.g XWiki.NewUser)
The actual full code can be viewed at github e.g. for the 7.2 release:
https://github.com/xwiki/xwiki-platform/blob/xwiki-platform-7.2/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java#L3366
Finally to distinguish between rights only given to a specific page, and rights given to a page and all its subpages: if you want a rights object to be valid for subpages, too, do not add it to the page itself, but create a special subpage with name WebPreferences and add an object of type XWiki.XWikiGlobalRights (with the same fields) to that page.
Some further pointers:
for more details how the access rights work, see http://platform.xwiki.org/xwiki/bin/view/AdminGuide/Access+Rights especially the reference section: "An overview of permissions"
If you have installed the "Admin Tools" extension, you can view the "ShowRights" page to see all right objects in you wiki.
I am using the service account model and Google's Admin SDK Java API to retrieve and modify users.
The goal is to add an alias for an existing user.
Alias newAlias = new Alias();
newAlias.setId(userID);
newAlias.setAlias(alias);
Directory.Users.Aliases.Insert request = directory.users().aliases().insert(userID, newAlias);
request.execute();
execute() fails 100% of the time with the error message:
"Value set through a parameter is inconsistent with a value set in the request"
but of course does not identify the problem parameter or value, or provide a suggestion.
I tried all 8 combinations of scoped (or not scoped) userID and alias in newAlias, and userID in the request, with the same result. By all 8 combinations, I mean:
newAlias.setId(userID);
newAlias.setAlias(alias);
insert(userID, newAlias);
newAlias.setId(userID#domain.com);
newAlias.setAlias(alias#domain.com);
insert(userID#domain.com, newAlias);
and so on...
Any ideas greatly appreciated.
I think it is worth adding that, while I believe the above approach is correct (using Directory.Aliases.Insert) and that I am missing some critical information or made a mistake, I also attempted to add the alias by updating the User object instead of Aliases, something like this:
List<String> aliases = new ArrayList<String>();
aliases.add(scopedAlias); //userid#domain.com
User user = new User();
user = retrieveUser(uid); //Gets current record from Google
user.setAliases(aliases);
Directory.Users.Update request
= directory.users().update(uid, user);
request.execute();
That did not work either.
Anyone have an example of working code?
I've gotten aliases inserted using the following:
Alias alias = new Alias();
alias.setAlias(aliasString);
directory.users().aliases().insert(userId, alias).execute();
I don't have anything in the way of insight as to why your approach isn't working or why my approach works, but there you go.
S. McKinley's suggestion worked.
The key difference:
I had been including the call:
alias.setId(userId);
or
alias.setId(scopedUserId); //userId#domain
Either one resulted in the "parameter is inconsistent with a value" error. Leave it out and the alias gets created.
I was able to find the customerId as follows
Go to admin.google.com
Security -> Set up single sign-on (SSO)
You will see URLs like this:
https://accounts.google.com/o/saml2/idp?idpid=Cxxxxxxxx
That Cxxxxxxxx is your customerId
I'm new to Drools Expert, currently from the Sample project of the drools what I can only do is print something to the console. Now I integrate drools to a web project and It was successful, I was be able to print something to the console depending on the interaction of the user to the page.
My rules currently is like this:
rule "A test Rule"
when
m: FLTBean ( listeningScore == 1, test : listeningScore )
then
System.out.println( test );
end
So what if I want to print it out to a web page? How would I do that? Do I need to use return to return some value back to the java page and render it to the page?
In order to display something on a web page, then you need to be using the API to invoke Drools and get some output, which can then be rendered by your web application.
Therefore, you need to consider how to get output from it within your Java code. There are a few ways of doing this.
For example, when performing a simple action such as validating a request, then just operate on the request which you insert. For instance:
rule "IBAN doesn't begin with a country ISO code."
no-loop
when
$req: IbanValidationRequest($iban:iban, $country:iban.substring(0, 2))
not Country(isoCode == $country) from countryList
then
$req.reject("The IBAN does not begin with a 2-character country code. '" + $country + "' is not a country.");
update($req);
end
In that example, I'm calling a "reject" method on the fact which I inserted. That modifies the inserted fact, so that after rules execution, I have an object in my Java code, with a flag to indicate whether it was rejected or not. This method works well for stateless knowledge sessions. i.e.
Java code - Insert request fact via API
Drools rule - Modify the request fact (flag rejection, annotate, set properties, etc)
Java code - Look at the fact to see what was done to it
The following code example of how to perform this interaction is taken from the following full colass:
https://github.com/gratiartis/sctrcd-payment-validation-web/blob/master/src/main/java/com/sctrcd/payments/validation/payment/RuleBasedPaymentValidator.java
// Create a new knowledge session from an existing knowledge base
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
// Create a validation request
PaymentValidationRequest request = new PaymentValidationRequest(payment);
// A stateless session is executed with a collection of Objects, so we
// create that collection containing just our request.
List<Object> facts = new ArrayList<Object>();
facts.add(request);
// And execute the session with that request
ksession.execute(facts);
// At this point, rules such as that above should have been activated.
// The rules modify the original request fact, setting a flag to indicate
// whether it is valid and adding annotations to indicate if/why not.
// They may have added annotations to the request, which we can now read.
FxPaymentValidationResult result = new FxPaymentValidationResult();
// Get the annotations that were added to the request by the rules.
result.addAnnotations(request.getAnnotations());
return result;
An alternative in a stateful session would be that rules could insert facts into working memory. After executing the rules, you can then query the session via the API and retrieve one or more result objects. You can get all facts in the session using the getObjects() method of the KnowledgeSession. To get facts with particular properties, there is also a getObjects(ObjectFilter) method. The project linked below has examples of using these methods in the KnowledgeEnvironment and DroolsUtil classes.
Alternatively, you could insert a service as a global variable. The rules could then invoke methods on that service.
For an example of how to use Drools within a web application, I knocked up this web site recently, which provides a REST API to invoke Drools rules and get responses.
https://github.com/gratiartis/sctrcd-payment-validation-web
If you have Maven installed, you should be able to try it out pretty quickly, and play around with the code.
I am working on an existing Web based application.
Now, I need to secure the application against what I think is called url hacking. For instance, if the customer with customerId 1 is logged in and viewing his profile, the following http get variable will be visible in the address field: customerId=1.
I need to prevent a customer from being able to set customerId=2 and see the profile of another customer.
The problem is that, the application is already in production and in good working condition, so the changes should be minimal with respect to this change.
How is this best achieved?
Any sugggestions/comments?
why do you give the id in the URL when the user should only be allowed to change his profile? I don't see any need for this. Rather get the current user from SecurityConext and display its profile on an URL without the id.
with the new information you gave in the comments I suggest sth. like this:
just check if the given orderid in the URL belongs to the current user.
You're saying you use "normal web based Application" so I assume Servlet/jsp based. In your servlet you would do something like this:
int orderId = Integer.parseInt(request.getParameter("orderId"));
String username = request.getUserPrincipal().getName();
/*now you need to check if username match with the username of the order e.g. by using hibernate to get the order by id and check its user and if not throw PermissionDeniedException or similiar*/
95% agree with Korgen's answer above.
5% - if you want to allow administrator access to edit user profiles using the same functionality just switch to UUID to identify edited user.