/*
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.services.jcr.access;
import org.exoplatform.services.security.IdentityConstants;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import javax.jcr.RepositoryException;
/**
* Created by The eXo Platform SAS<br>
*
* The AccessControlList represents a list of access control entries.
*
* @author Gennady Azarenkov
* @version $Id: AccessControlList.java 14556 2008-05-21 15:22:15Z pnedonosko $
* @LevelAPI Experimental
*/
public class AccessControlList implements Externalizable
{
private static final long serialVersionUID = 5848327750178729120L;
public static final String DELIMITER = ";";
private String owner;
private final List<AccessControlEntry> accessList;
public AccessControlList()
{
this(IdentityConstants.SYSTEM);
}
/**
* Default ACL owned by ownerName.
*
* @param ownerName
* owner name
*/
AccessControlList(String ownerName)
{
this.owner = ownerName;
this.accessList = new ArrayList<AccessControlEntry>();
for (String str : PermissionType.ALL)
{
accessList.add(new AccessControlEntry(IdentityConstants.ANY, str));
}
}
/**
* Create ACL from owner name and collection of permission entries.
*
* @param owner
* @param accessList
* - permission entries
*/
public AccessControlList(String owner, List<AccessControlEntry> accessList)
{
this.owner = owner;
this.accessList = accessList;
}
/**
* @return returns <code>true</code> if the permission list has been set, <code>false</code> otherwise
*/
public boolean hasPermissions()
{
return accessList != null;
}
/**
* @return returns <code>true</code> if the owner has been set, <code>false</code> otherwise
*/
public boolean hasOwner()
{
return owner != null;
}
/**
* Adds permissions
* @param rawData A semicolon separated string representing the list of permission entries to add,
* knowing that the syntax of a permission entry is ${identity} [read|add_node|set_property|remove]
*/
public void addPermissions(String rawData) throws RepositoryException
{
StringTokenizer listTokenizer = new StringTokenizer(rawData, AccessControlList.DELIMITER);
if (listTokenizer.countTokens() < 1)
throw new RepositoryException("AccessControlList " + rawData + " is empty or have a bad format");
while (listTokenizer.hasMoreTokens())
{
String entry = listTokenizer.nextToken();
try
{
accessList.add(AccessControlEntry.parse(entry));
}
catch (IllegalArgumentException e)
{
throw new RepositoryException("AccessControlEntry " + entry + " is empty or have a bad format", e);
}
}
}
/**
* Adds a set of permission types to a given identity
* @param identity the member identity
* @param perm an array of permission types to add
*/
public void addPermissions(String identity, String[] perm) throws RepositoryException
{
for (String p : perm)
{
accessList.add(new AccessControlEntry(identity, p));
}
}
/**
* Removes all the permissions of a given identity
* @param identity the member identity
*/
public void removePermissions(String identity)
{
for (Iterator<AccessControlEntry> iter = accessList.iterator(); iter.hasNext();)
{
AccessControlEntry a = iter.next();
if (a.getIdentity().equals(identity))
iter.remove();
}
}
/**
* Removes the permission corresponding to the given identity and the given permission type
* @param identity the member identity
* @param permission the permission type
*/
public void removePermissions(String identity, String permission)
{
for (Iterator<AccessControlEntry> iter = accessList.iterator(); iter.hasNext();)
{
AccessControlEntry a = iter.next();
if (a.getIdentity().equals(identity) && a.getPermission().equals(permission))
iter.remove();
}
}
/**
* Get owner.
*
* @return Returns the owner.
*/
public String getOwner()
{
return owner;
}
/**
* Sets owner.
*
* @param owner the owner
*/
public void setOwner(String owner)
{
this.owner = owner;
}
/**
* Gives all the permission entries
* @return a safe copy of all the permission entries
*/
public List<AccessControlEntry> getPermissionEntries()
{
List<AccessControlEntry> list = new ArrayList<AccessControlEntry>();
for (int i = 0, length = accessList.size(); i < length; i++)
{
AccessControlEntry entry = accessList.get(i);
list.add(new AccessControlEntry(entry.getIdentity(), entry.getPermission()));
}
return list;
}
/**
* @param identity the member identity
* @return returns the list of all the permission types associated to the given identity
*/
public List<String> getPermissions(String identity)
{
List<String> permissions = new ArrayList<String>();
for (int i = 0, length = accessList.size(); i < length; i++)
{
AccessControlEntry entry = accessList.get(i);
if (entry.getIdentity().equals(identity))
permissions.add(entry.getPermission());
}
return permissions;
}
/**
* {@inheritDoc}
*/
public boolean equals(Object obj)
{
if (obj == this)
return true;
if (obj instanceof AccessControlList)
{
AccessControlList another = (AccessControlList)obj;
// check owners, it may be null
if (!((owner == null && another.owner == null) || (owner != null && owner.equals(another.owner))))
{
return false;
}
// check accessList
List<AccessControlEntry> anotherAccessList = another.accessList;
if (accessList == null && anotherAccessList == null)
{
return true;
}
else if (accessList != null && anotherAccessList != null && accessList.size() == anotherAccessList.size())
{
// check content of both accessLists
for (int i = 0; i < accessList.size(); i++)
{
if (!accessList.get(i).getAsString().equals(anotherAccessList.get(i).getAsString()))
{
return false;
}
}
return true;
}
else
{
return false;
}
//return dump().equals(another.dump());
}
return false;
}
/**
* Gives a String representation of the {@link AccessControlList} with all the details
*/
public String dump()
{
StringBuilder res = new StringBuilder("OWNER: ").append(owner != null ? owner : "null").append("\n");
if (accessList != null)
{
for (AccessControlEntry a : accessList)
{
res.append(a.getAsString()).append("\n");
}
}
else
{
res.append("null");
}
return res.toString();
}
/**
* {@inheritDoc}
*/
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
// reading owner
byte[] buf;
int ownLength = in.readInt();
if (ownLength != 0)
{
buf = new byte[ownLength];
in.readFully(buf);
this.owner = new String(buf, "UTF-8");
}
else
{
this.owner = null;
}
accessList.clear();
// reading access control entrys size
int listSize = in.readInt();
for (int i = 0; i < listSize; i++)
{
// reading access control entrys identity
buf = new byte[in.readInt()];
in.readFully(buf);
String ident = new String(buf, "UTF-8");
// reading permission
buf = new byte[in.readInt()];
in.readFully(buf);
String perm = new String(buf, "UTF-8");
accessList.add(new AccessControlEntry(ident, perm));
}
}
/**
* {@inheritDoc}
*/
public void writeExternal(ObjectOutput out) throws IOException
{
// Writing owner
if (owner != null)
{
out.writeInt(owner.getBytes().length);
out.write(owner.getBytes());
}
else
{
out.writeInt(0);
}
// writing access control entrys size
out.writeInt(accessList.size());
for (AccessControlEntry entry : accessList)
{
// writing access control entrys identity
out.writeInt(entry.getIdentity().getBytes().length);
out.write(entry.getIdentity().getBytes());
// writing permission
out.writeInt(entry.getPermission().getBytes().length);
out.write(entry.getPermission().getBytes());
}
}
/**
* Gives access to the size of existing permissions.
*
* @return size of access list
*/
public int getPermissionsSize()
{
return accessList.size();
}
/**
* Special method for internal JCR use.
*
* @return list of AccessControlEntry
*/
List<AccessControlEntry> getPermissionsList()
{
return accessList;
}
}