/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-06 Wolfgang M. Meier
* wolfgang@exist-db.org
* http://exist.sourceforge.net
*
* This program 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
* of the License, or (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id:
*/
package org.exist.security;
import java.io.DataInput;
import java.io.IOException;
import java.util.StringTokenizer;
import org.exist.util.SyntaxException;
/**
* Manages the permissions assigned to a ressource. This includes
* the user who owns the ressource, the owner group and the permissions
* for user, group and others. Permissions are encoded in a single byte
* according to common unix conventions.
*
*@author Wolfgang Meier <wolfgang@exist-db.org>
*/
public class UnixStylePermission implements Permission {
//default Unix style permissions for a resource
public final static int DEFAULT_PERM = 0755;
//default UnixStylePermission
public final static Permission SYSTEM_DEFAULT = new UnixStylePermission(DEFAULT_PERM);
//owner, default to DBA
private String owner = SecurityManager.DBA_USER;
private String ownerGroup = SecurityManager.DBA_GROUP;
//permissions
private int permissions = DEFAULT_PERM;
public UnixStylePermission() { }
/**
* Construct a Permission with given permissions
*
*@param permissions Description of the Parameter
*/
public UnixStylePermission(int permissions) {
this.permissions = permissions;
}
/**
* Construct a permission with given user, group and
* permissions
*
*@param user Description of the Parameter
*@param group Description of the Parameter
*@param permissions Description of the Parameter
*/
public UnixStylePermission(String user, String group, int permissions) {
this.owner = user;
this.ownerGroup = group;
this.permissions = permissions;
}
/**
* Get the active permissions for group
*
*@return The groupPermissions value
*/
public int getGroupPermissions() {
return ( permissions & 0x38 ) >> 3;
}
/**
* Gets the user who owns this resource
*
*@return The owner value
*/
public String getOwner() {
return owner;
}
/**
* Gets the group
*
*@return The ownerGroup value
*/
public String getOwnerGroup() {
return ownerGroup;
}
/**
* Get the permissions
*
*@return The permissions value
*/
public int getPermissions() {
return permissions;
}
/**
* Get the active permissions for others
*
*@return The publicPermissions value
*/
public int getPublicPermissions() {
return permissions & 0x7;
}
/**
* Get the active permissions for the owner
*
*@return The userPermissions value
*/
public int getUserPermissions() {
return ( permissions & 0x1c0 ) >> 6;
}
/**
* Read the Permission from an input stream
*
*@param istream Description of the Parameter
*@exception IOException Description of the Exception
*/
public void read( DataInput istream ) throws IOException {
owner = istream.readUTF();
ownerGroup = istream.readUTF();
permissions = istream.readByte();
}
/**
* Set the owner group
*
*@param group The new group value
*/
public void setGroup( String group ) {
this.ownerGroup = group;
}
/**
* Sets permissions for group
*
*@param perm The new groupPermissions value
*/
public void setGroupPermissions( int perm ) {
permissions = permissions | ( perm << 3 );
}
/**
* Set the owner passed as User object
*
*@param user The new owner value
*/
public void setOwner( User user ) {
// FIXME: assume guest identity if user gets lost due to a database corruption
if(user == null) {
this.owner = SecurityManager.GUEST_USER;
} else
this.owner = user.getName();
//this.ownerGroup = user.getPrimaryGroup();
}
/**
* Set the owner
*
*@param user The new owner value
*/
public void setOwner( String user ) {
this.owner = user;
}
/**
* Set permissions using a string. The string has the
* following syntax:
*
* [user|group|other]=[+|-][read|write|update]
*
* For example, to set read and write permissions for the group, but
* not for others:
*
* group=+read,+write,other=-read,-write
*
* The new settings are or'ed with the existing settings.
*
*@param str The new permissions
*@exception SyntaxException Description of the Exception
*/
public void setPermissions( String str ) throws SyntaxException {
StringTokenizer tokenizer = new StringTokenizer( str, ",= " );
String token;
int shift = -1;
while ( tokenizer.hasMoreTokens() ) {
token = tokenizer.nextToken();
if ( token.equalsIgnoreCase( USER_STRING ) )
shift = 6;
else if ( token.equalsIgnoreCase( GROUP_STRING ) )
shift = 3;
else if ( token.equalsIgnoreCase( OTHER_STRING ) )
shift = 0;
else {
char modifier = token.charAt( 0 );
if ( !( modifier == '+' || modifier == '-' ) )
throw new SyntaxException( "expected modifier +|-" );
else
token = token.substring( 1 );
if ( token.length() == 0 )
throw new SyntaxException( "'read', 'write' or 'update' " +
"expected in permission string" );
int perm;
if ( token.equalsIgnoreCase( "read" ) )
perm = READ;
else if ( token.equalsIgnoreCase( "write" ) )
perm = WRITE;
else
perm = UPDATE;
switch ( modifier ) {
case '+':
permissions = permissions | ( perm << shift );
break;
default:
permissions = permissions & ( ~( perm << shift ) );
break;
}
}
}
}
/**
* Set permissions
*
*@param perm The new permissions value
*/
public void setPermissions( int perm ) {
this.permissions = perm;
}
/**
* Set permissions for others
*
*@param perm The new publicPermissions value
*/
public void setPublicPermissions( int perm ) {
permissions = permissions | perm;
}
/**
* Set permissions for the owner
*
*@param perm The new userPermissions value
*/
public void setUserPermissions( int perm ) {
permissions = permissions | ( perm << 6 );
}
/**
* Format permissions
*
*@return Description of the Return Value
*/
public String toString() {
final char ch[] = {
( permissions & ( READ << 6 ) ) == 0 ? '-' : 'r',
( permissions & ( WRITE << 6 ) ) == 0 ? '-' : 'w',
( permissions & ( UPDATE << 6 ) ) == 0 ? '-' : 'u',
( permissions & ( READ << 3 ) ) == 0 ? '-' : 'r',
( permissions & ( WRITE << 3 ) ) == 0 ? '-' : 'w',
( permissions & ( UPDATE << 3 ) ) == 0 ? '-' : 'u',
( permissions & READ ) == 0 ? '-' : 'r',
( permissions & WRITE ) == 0 ? '-' : 'w',
( permissions & UPDATE ) == 0 ? '-' : 'u'
};
return new String(ch);
}
/**
* Check if user has the requested permissions for this resource.
*
*@param user The user
*@param perm The requested permissions
*@return true if user has the requested permissions
*/
public boolean validate( User user, int perm ) {
// group dba has full access
if ( user.hasDbaRole() )
return true;
// check if the user owns this resource
if ( user.getName().equals( owner ) )
return validateUser( perm );
// check groups
String[] groups = user.getGroups();
for (int i = 0; i < groups.length; i++) {
if ( groups[i].equals( ownerGroup ) )
return validateGroup( perm );
}
// finally, check public access rights
return validatePublic( perm );
}
private final boolean validateGroup( int perm ) {
perm = perm << 3;
return ( permissions & perm ) == perm;
}
private final boolean validatePublic( int perm ) {
return ( permissions & perm ) == perm;
}
private final boolean validateUser( int perm ) {
perm = perm << 6;
return ( permissions & perm ) == perm;
}
}