Document permissions Content Engine API - access-control

I'm trying to remove/add the groups from security of a document in FileNet using CPE API. I am able to remove wihtout any issues. However, when I try to add the groups that are missing, by inheriting from document class, groups get added without full permissions. For example, I remove "author" group and when I try to add the same group back, it does not have all the permissions.
Remove groups:
AccessPermissionList apl = doc.get_Permissions();
Iterator iter = apl.iterator();
while (iter.hasNext())
{
AccessPermission ap = (AccessPermission)iter.next();
if(ap.get_GranteeName().contains("group name")){
iter.remove();
}
}
doc.set_Permissions(apl);
doc.save(RefreshMode.NO_REFRESH);
Add groups:
DocumentClassDefinition docClassDef = Factory.DocumentClassDefinition.fetchInstance(os, classID, null);
AccessPermissionList docClassApl = docClassDef.get_Permissions();
Iterator docClassApliter = docClassApl.iterator();
for(Object obj : docClassApl)
{
AccessPermission ap = (AccessPermission)obj;
if(!apl.contains(ap)){
apl.add(ap);
}
}
doc.set_Permissions(apl);
doc.save(RefreshMode.NO_REFRESH);
RESOLVED:
Had to use DefaultInstanceSecurity rather than regular security as the permissions in both instances were different. So just updated the following line of code:
AccessPermissionList docClassApl = docClassDef.get_DefaultInstancePermissions();

You need to set AccessMask too. Like below:
AccessPermission ap;
ap.set_AccessMark ( new Integer (AccessLevel.FULL_CONTROL_DOCUMENT_AS_INT));
//AccessLevel.WRITE_DOCUMENT_AS_INT
//AccessLevel.MAJOR_VERSION_DOCUMENT_AS_INT
Version 5.2.0 onwards, AccessLevel is deprecated but you can give it a try. AccessRight is the replacement now. Refer this.
Update
public static void setPermissions(Document doc) throws IOException {
//In cpetarget.properties file
//cpetarget.security=Administrator:FULL_CONTROL,p8admin:MODIFY_PROPERTIES
InputStream input = new FileInputStream("cpetarget.properties");
java.util.Properties prop = new java.util.Properties();
prop.load(input);
List<String> strList = new ArrayList<String>(Arrays.asList(prop.getProperty("cpetarget.security").split(",")));
AccessPermissionList apl = doc.get_Permissions();
Iterator<AccessPermission> itr = apl.iterator();
List<AccessPermissionList> oldPermissionsList = new ArrayList<AccessPermissionList>();
oldPermissionsList.addAll(apl);
// Remove all your old permissions here
apl.removeAll(oldPermissionsList);
// Add all your new permissions here
try {
for (String str : strList) {
String[] strArray = str.split(":");
AccessPermission permission = Factory.AccessPermission.createInstance();
permission.set_GranteeName(strArray[0]);
permission.set_AccessType(AccessType.ALLOW);
permission.set_InheritableDepth(new Integer(0));
//permission.set_InheritableDepth(new Integer(0)); // this object only
//permission.set_InheritableDepth(new Integer(-1));this object and all children
//permission.set_InheritableDepth(new Integer(1)); this object and immediate children
if (strArray[1].equalsIgnoreCase("FULL_CONTROL")) {
permission.set_AccessMask(new Integer(AccessLevel.FULL_CONTROL_DOCUMENT_AS_INT));
//permission.set_AccessMask(AccessRight.MAJOR_VERSION_AS_INT);
}
if (strArray[1].equalsIgnoreCase("READ_ONLY")) {
permission.set_AccessMask(new Integer(AccessLevel.VIEW_AS_INT));
}
if (strArray[1].equalsIgnoreCase("MODIFY_PROPERTIES")) {
permission.set_AccessMask(new Integer(AccessLevel.WRITE_DOCUMENT_AS_INT));
}
if (strArray[1].equalsIgnoreCase("MAJOR_VERSIONING")) {
permission.set_AccessMask(new Integer(AccessLevel.MAJOR_VERSION_DOCUMENT_AS_INT));
}
AccessPermissionList permissions = doc.get_Permissions();
permissions.add(permission);
doc.set_Permissions(permissions);
doc.save(RefreshMode.REFRESH);
System.out.println("Done");
}
} catch (Exception e) {
e.printStackTrace();
}
}

Related

Hippo CMS 7.9 Facets

I'm trying to implement facets and also create a catalog component.
My original approach was to use the:
org.onehippo.cms7.essentials.components.EssentialsContentComponent
However it doesn't seem like it's available for 7.9.
My next approach is to extend the PresentationList Component however the documentation isn't that clear of creating the values for the main and sub categories.
I would like to use this code for my component I'm just not sure once again where to place my Category (values).
try {
HstRequestContext requestContext = request.getRequestContext();
HippoBean scope = requestContext.getSiteContentBaseBean();
PresentationPageableListInfo info = getComponentParametersInfo(request);
LandingPage presentationPage = null;
String resolvedContentPath = PathUtils.normalizePath(requestContext
.getResolvedSiteMapItem().getRelativeContentPath());
createAndExecuteSearch(request, info, scope, (BaseFilter) null,
null, resolvedContentPath);
if (scope instanceof HippoFolderBean) {
presentationPage = getFirstLandingPageInFolder(request,
(HippoFolderBean) scope);
}
if (presentationPage != null) {
request.setAttribute("document", presentationPage);
}
if (request.getPathInfo().toLowerCase().contains("facet/")) {
request.setAttribute("faceted", true);
}
} catch (Exception e) {
throw new HstComponentException("Failed to query presentations.", e);
}
have you tried these pages :
http://www.onehippo.org/7_9/library/concepts/faceted-navigation/faceted-navigation-configuration.html
http://www.onehippo.org/7_9/library/setup/hst-components/facets-component.html

Web API Help pages - customizing Property documentation

I have my web api and I added the web api help pages to auto-generate my documentation. It's working great for methods where my parameters are listed out, but I have a method like this:
public SessionResult PostLogin(CreateSessionCommand request)
And, on my help page, it is only listing the command parameter in the properties section. However, in the sample request section, it lists out all of the properties of my CreateSessionCommand class.
Parameters
Name | Description | Additional information
request | No documentation available. | Define this parameter in the request body.
I would like it instead to list all of the properties in my CreateSessionCommand class. Is there an easy way to do this?
So, I managed to devise a workaround for this problem, in case anyone is interested.
In HelpPageConfigurationExtensions.cs I added the following extension method:
public static void AlterApiDescription(this ApiDescription apiDescription, HttpConfiguration config)
{
var docProvider = config.Services.GetDocumentationProvider();
var addParams = new List<ApiParameterDescription>();
var removeParams = new List<ApiParameterDescription>();
foreach (var param in apiDescription.ParameterDescriptions)
{
var type = param.ParameterDescriptor.ParameterType;
//string is some special case that is not a primitive type
//also, compare by full name because the type returned does not seem to match the types generated by typeof
bool isPrimitive = type.IsPrimitive || String.Compare(type.FullName, typeof(string).FullName) == 0;
if (!isPrimitive)
{
var properties = from p in param.ParameterDescriptor.ParameterType.GetProperties()
let s = p.SetMethod
where s.IsPublic
select p;
foreach (var property in properties)
{
var documentation = docProvider.GetDocumentation(new System.Web.Http.Controllers.ReflectedHttpParameterDescriptor()
{
ActionDescriptor = param.ParameterDescriptor.ActionDescriptor,
ParameterInfo = new CustomParameterInfo(property)
});
addParams.Add(new ApiParameterDescription()
{
Documentation = documentation,
Name = property.Name,
Source = ApiParameterSource.FromBody,
ParameterDescriptor = param.ParameterDescriptor
});
}
//since this is a complex type, select it to be removed from the api description
removeParams.Add(param);
}
}
//add in our new items
foreach (var item in addParams)
{
apiDescription.ParameterDescriptions.Add(item);
}
//remove the complex types
foreach (var item in removeParams)
{
apiDescription.ParameterDescriptions.Remove(item);
}
}
And here is the Parameter info instanced class I use
internal class CustomParameterInfo : ParameterInfo
{
public CustomParameterInfo(PropertyInfo prop)
{
base.NameImpl = prop.Name;
}
}
Then, we call the extension in another method inside the extensions class
public static HelpPageApiModel GetHelpPageApiModel(this HttpConfiguration config, string apiDescriptionId)
{
object model;
string modelId = ApiModelPrefix + apiDescriptionId;
if (!config.Properties.TryGetValue(modelId, out model))
{
Collection<ApiDescription> apiDescriptions = config.Services.GetApiExplorer().ApiDescriptions;
ApiDescription apiDescription = apiDescriptions.FirstOrDefault(api => String.Equals(api.GetFriendlyId(), apiDescriptionId, StringComparison.OrdinalIgnoreCase));
if (apiDescription != null)
{
apiDescription.AlterApiDescription(config);
HelpPageSampleGenerator sampleGenerator = config.GetHelpPageSampleGenerator();
model = GenerateApiModel(apiDescription, sampleGenerator);
config.Properties.TryAdd(modelId, model);
}
}
return (HelpPageApiModel)model;
}
The comments that are used for this must be added to the controller method and not the properties of the class object. This might be because my object is part of an outside library
this should go as an addition to #Josh answer. If you want not only to list properties from the model class, but also include documentation for each property, Areas/HelpPage/XmlDocumentationProvider.cs file should be modified as follows:
public virtual string GetDocumentation(HttpParameterDescriptor parameterDescriptor)
{
ReflectedHttpParameterDescriptor reflectedParameterDescriptor = parameterDescriptor as ReflectedHttpParameterDescriptor;
if (reflectedParameterDescriptor != null)
{
if (reflectedParameterDescriptor.ParameterInfo is CustomParameterInfo)
{
const string PropertyExpression = "/doc/members/member[#name='P:{0}']";
var pi = (CustomParameterInfo) reflectedParameterDescriptor.ParameterInfo;
string selectExpression = String.Format(CultureInfo.InvariantCulture, PropertyExpression, pi.Prop.DeclaringType.FullName + "." + pi.Prop.Name);
XPathNavigator methodNode = _documentNavigator.SelectSingleNode(selectExpression);
if (methodNode != null)
{
return methodNode.Value.Trim();
}
}
else
{
XPathNavigator methodNode = GetMethodNode(reflectedParameterDescriptor.ActionDescriptor);
if (methodNode != null)
{
string parameterName = reflectedParameterDescriptor.ParameterInfo.Name;
XPathNavigator parameterNode = methodNode.SelectSingleNode(String.Format(CultureInfo.InvariantCulture, ParameterExpression, parameterName));
if (parameterNode != null)
{
return parameterNode.Value.Trim();
}
}
}
}
return null;
}
and CustomParameterInfo class should keep property info as well:
internal class CustomParameterInfo : ParameterInfo
{
public PropertyInfo Prop { get; private set; }
public CustomParameterInfo(PropertyInfo prop)
{
Prop = prop;
base.NameImpl = prop.Name;
}
}
This is currently not supported out of the box. Following bug is kind of related to that:
http://aspnetwebstack.codeplex.com/workitem/877

PublicAccess permissions not working in Umbraco 6

I am trying to display a table listing some documents (nodes) to the users. Those documents are protected using role permissions (right click > Public Access > Role Permissions) and I want to show only those to which this user has access.
After checking here and there, I've seen that there isn't any "Node.Permissions" way, so you have to go through Access.HasAccess().
I have used that, and I have set the permissions, but when I use the method it returns always true. What am I doing wrong?
This is the code to build the list of nodes, which works perfectly:
public static List<Node> GetAllNodeChildrenRecursively(int nodeId, string typeName)
{
var node = new Node(nodeId);
var lstNodes = new List<Node>();
foreach (Node childNode in node.Children)
{
var child = childNode;
if (child.NodeTypeAlias == typeName)
{
lstNodes.Add(childNode);
}
if (child.Children.Count > 0)
{
lstNodes.AddRange(GetAllNodeChildrenRecursively(childNode.Id, typeName));
}
}
return lstNodes;
}
This is the code to remove those I haven't access to:
var availableNodes = new List<Node>();
foreach(Node n in nodes)
{
if(Access.HasAccces(n.Id, memberId))
{
availableNodes.Add(n);
}
}
return availableNodes;
Well, Access.HasAccess returns always true, and the member I am using to test is not part of the MemberGroup that has access to that node. Am I setting permissions wrong or not checking it properly or what?
I'm lost.
As far as I know you should use the following method:
*There are a few different calls to HasAccess so it might depend on your version of Umbraco as well.
var availableNodes = new List<Node>();
try
{
//this will throw an argument exception if there is not a current user logged in
var currentMember = System.Web.Security.Membership.GetUser();
foreach (Node n in retVal)
{
if (Access.HasAccess(n.Id, n.Path, currentMember))
{
availableNodes.Add(n);
}
}
}
catch(ArgumentException e)
{
//do something when there is not a logged in member
}
return availableNodes;

How can I make my lucene search "global" (i.e. for all groups) in liferay?

I use the following in a search container to find the projects in a given group:
SearchContext searchContext = SearchContextFactory.getInstance(request);
searchContext.setStart(searchContainer.getStart());
searchContext.setKeywords(keywords);
searchContext.setEnd(searchContainer.getEnd());
results = ProjectLocalServiceUtil.getSearchedProjects(searchContext);
total = ProjectLocalServiceUtil.getSearchedProjectsCount(searchContext);
The methods getSearchedProjects translates from search results to a list of projects:
public List<Project> getSearchedProjects(SearchContext context) throws SearchException {
Indexer indexer = IndexerRegistryUtil.getIndexer(Project.class);
Hits results = indexer.search(context);
List<Project> projects = new ArrayList<Project>();
for (int i = 0; i < results.getDocs().length; i++) {
com.liferay.portal.kernel.search.Document doc = results.doc(i);
long projectId=GetterUtil.getLong(doc.get(Field.ENTRY_CLASS_PK));
Project project = null;
try {
project = ProjectLocalServiceUtil.getProject(projectId);
projects.add(project);
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
return projects;
}
The results are as I expect when the search portlet is placed in the group referenced in the group I set in my projectIndexer's doGetDocument method:
document.addKeyword(Field.GROUP_ID, groupId);
document.addKeyword(Field.SCOPE_GROUP_ID, groupId);
but I would like to use the portlet to search from another group.
I tried to set the list of groupIds in the portlet, using
searchContext.setGroupIds(new long[] {projectHolder.getGroupId()});
but I still don't get any results in the search.
Any pointers on how I can search 'across groups' ?
Alain
I found the answer to my question. In order for
searchContext.setGroupIds(new long[] {group1ID, group2Id});
to have an effect the searchContext should NOT have groupId as one of its attributes.
SearchContextFactory adds GroupId in the attributes (see the extract below), so after the call to getInstance, you need to remove groupId from the attributes :
SearchContext searchContext = SearchContextFactory.getInstance(request);
Map<String, Serializable> attributes = searchContext.getAttributes();
attributes.remove("groupId");
Hope this helps someone someday.
Alain
Below, the extract from SearchContextFactory.getInstance(HttpServletRequest request) that (I believe - didn't debug it) sets the groupId attribute from the parameters :
// Extract from SearchContextFactory.java
Map<String, String[]> parameters = request.getParameterMap();
for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
String name = entry.getKey();
String[] values = entry.getValue();
if ((values != null) && (values.length > 0)) {
if (values.length == 1) {
attributes.put(name, values[0]);
}
else {
attributes.put(name, values);
}
}
}
searchContext.setAttributes(attributes);

Cannot create list in SharePoint 2010 using Client Object Model

I am trying to utilize SharePoint 2010 Client Object Model to create a List based on a custom template. Here's my code:
public void MakeList(string title, string listTemplateGUID, int localeIdentifier)
{
string message;
string listUrl;
ListTemplate template;
ListCreationInformation listInfo;
ListTemplateCollection templatesCollection;
try
{
listUrl = title.Replace(spaceChar, string.Empty);
templatesCollection = clientContext.Site.GetCustomListTemplates(clientContext.Web);
clientContext.Load(templatesCollection);
clientContext.ExecuteQuery();
foreach (ListTemplate t in templatesCollection)
{
if (t.InternalName == listTemplate)
{
template = t;
break;
}
}
listInfo = new ListCreationInformation();
listInfo.TemplateType = template.ListTemplateTypeKind;
//listInfo.TemplateFeatureId = template.FeatureId;
listInfo.Url = listUrl;
listInfo.Title = title;
listInfo.Description = string.Empty;
listInfo.QuickLaunchOption = QuickLaunchOptions.On;
site.Lists.Add(listInfo);
clientContext.ExecuteQuery();
return RetrieveList(title, listUrl);
}
catch (ServerException ex)
{
//...
}
}
A few unexpected things happen when this code is run:
My template is derived from the default document library template. Now, the code above does not create the document library based on my template - it creates the default document library instead.
If I uncomment the //listInfo.TemplateFeatureId = template.FeatureId; the code throws the ServerException error: "Cannot complete this action. Please try again."
If I place listInfo.TemplateFeatureId = template.FeatureId; before listInfo.TemplateType = template.ListTemplateTypeKind; the end result is the same as under item 1 - the default document library is created.
Could anyone please help me realize what am I doing wrong? Thanks.