added code to auto-join new users to a new community, where necessary

This commit is contained in:
Eric J. Bowersox 2003-06-02 12:05:44 +00:00
parent 31e0cbe4a0
commit d72db2985b
12 changed files with 461 additions and 8 deletions

View File

@ -571,7 +571,7 @@ INSERT INTO userprop (uid, nsid, prop_name, prop_value) VALUES
(1, 10, 'locale', '_LOC:en_US'),
(1, 10, 'admin.flags', '_OS:A' ),
(1, 10, 'search.result.count', 'I20' ),
(1, 11, 'privacy', '_OS:' ),
(1, 11, 'privacy', '_OS:F' ),
(1, 11, 'name.given', '!Anonymous'),
(1, 11, 'name.family', '!Honyak' ),
(1, 11, 'locality', '!Nowhere' ),

View File

@ -77,6 +77,18 @@ public class LibraryCast
} // end booleanObject
public final boolean isBooleanFalse(Object o)
{
return Boolean.FALSE.equals(o);
} // end isBooleanFalse
public final boolean isBooleanTrue(Object o)
{
return Boolean.TRUE.equals(o);
} // end isBooleanTrue
public final int[] newIntArray(int size)
{
return new int[size];

View File

@ -42,6 +42,46 @@ import com.silverwrist.venice.iface.*;
*/
class CommunityImpl implements VeniceCommunity
{
/*--------------------------------------------------------------------------------
* Internal join cleanup task class.
*--------------------------------------------------------------------------------
*/
private class JoinCleanupTask
{
/*====================================================================
* Attributes
*====================================================================
*/
private int m_ugid;
private boolean m_is_group;
/*====================================================================
* Constructor
*====================================================================
*/
JoinCleanupTask(int ugid, boolean is_group)
{
m_ugid = ugid;
m_is_group = is_group;
} // end constructor
/*====================================================================
* External operations
*====================================================================
*/
void run() throws DatabaseException
{
m_ops.deleteSingleUseAuthData(m_id,m_ugid,m_is_group);
} // end run
} // end class JoinCleanupTask
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
@ -863,6 +903,9 @@ class CommunityImpl implements VeniceCommunity
*/
public Object getJoinRequirement(DynamoUser joiner) throws DatabaseException
{
if (logger.isDebugEnabled())
logger.debug("CommunityImpl.getJoinRequirement: " + joiner.getName() + " wants to join " + m_name);
// If the user is already a member, return the value that dictates that we are already a member.
if (m_users.getGroup(m_member_gid).isMember(joiner))
return Boolean.FALSE;
@ -899,4 +942,109 @@ class CommunityImpl implements VeniceCommunity
} // end getJoinRequirement
public synchronized boolean join(DynamoUser joiner, String auth_namespace, String auth_name, String source_info,
String auth_info) throws DatabaseException, DynamoSecurityException
{
if (logger.isDebugEnabled())
logger.debug("CommunityImpl.join: " + joiner.getName() + " joining " + m_name);
// If the user is already a member, return the value that dictates that we are already a member.
if (m_users.getGroup(m_member_gid).isMember(joiner))
return false;
boolean ok_to_join = false;
JoinCleanupTask task = null;
if (joiner.equals(m_srm.getAdminUser()))
ok_to_join = true;
else if (m_srm.getGlobalAcl().testPermission(joiner,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,"join.any"))
ok_to_join = true;
else
{ // Look to see if we can find the right entry to let the user in with.
boolean need_auth = false;
Object which = m_ops.getJoinEntryNull(m_id,joiner.getUID());
if ((which==null) && (auth_namespace!=null) && (auth_name!=null))
{ // OK, we may need to authenticate
need_auth = true;
which = m_ops.getJoinEntry(m_id,joiner.getUID(),m_nscache.namespaceNameToId(auth_namespace),auth_name,
source_info);
} // end which
if (which!=null)
{ // We can get in...see if we need to check authentication.
if (need_auth)
{ // Pull in the authentication data.
String stored_auth_data;
if (which instanceof Boolean)
stored_auth_data = m_ops.getAuthData(m_id,joiner.getUID(),false);
else
stored_auth_data = m_ops.getAuthData(m_id,((Integer)which).intValue(),true);
// Get the authenticator.
Authenticator auth = m_alook.findAuthenticator(auth_namespace,auth_name);
if (auth==null)
throw new IllegalArgumentException("invalid authenticator");
// Checkitout checkitout checkitout checkitout checkitout checkitout checkitout....
try
{ // attempt to authenticate
ok_to_join = auth.authenticate(stored_auth_data,auth_info);
} // end try
catch (AuthenticationException e)
{ // something went wrong...
DynamoSecurityException de = new DynamoSecurityException(CommunityImpl.class,"CommunityMessages",
"join.authFail",e);
de.setParameter(0,m_name);
throw de;
} // end catch
if (!ok_to_join)
{ // authentication failed - throw an error
DynamoSecurityException de = new DynamoSecurityException(CommunityImpl.class,"CommunityMessages",
"join.authFail");
de.setParameter(0,m_name);
throw de;
} // end if
} // end if
else // we're automatically OK to join
ok_to_join = true;
// Create the cleanup task.
if (which instanceof Boolean)
task = new JoinCleanupTask(joiner.getUID(),false);
else
task = new JoinCleanupTask(((Integer)which).intValue(),true);
} // end if
// else we can't join the group - fall through and eventually throw a DynamoSecurityException
} // end else
if (ok_to_join)
{ // we're OK to join this group!
m_users.getGroup(m_member_gid).addMember(m_users.getUser(m_host_uid),joiner);
if (task!=null)
task.run();
return true;
} // end if
// We cannot join - throw an exception.
DynamoSecurityException de = new DynamoSecurityException(CommunityImpl.class,"CommunityMessages",
"join.disallowed");
de.setParameter(0,m_name);
throw de;
} // end join
public boolean join(DynamoUser joiner) throws DatabaseException, DynamoSecurityException
{
return this.join(joiner,null,null,null,null);
} // end join
} // end class CommunityImpl

View File

@ -183,6 +183,8 @@ public class CommunityManager
private final List translateCIDArray(int[] array) throws DatabaseException
{
if (logger.isDebugEnabled())
logger.debug("translateCIDArray(): translating array of length " + array.length);
if (array.length==0)
return Collections.EMPTY_LIST;
ArrayList rc = new ArrayList(array.length);
@ -196,6 +198,8 @@ public class CommunityManager
{
if (caller.equals(user))
return true; // a user can always get his OWN member community list
if (m_srm.getAdminUser().equals(caller))
return true; // Administrator can do anything
if (m_srm.getGlobalAcl().testPermission(caller,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,
"see.member.community.lists"))
return true; // this user is permitted to see all member community lists
@ -335,8 +339,13 @@ public class CommunityManager
public List getMemberCommunities(DynamoUser caller, DynamoUser user)
throws DatabaseException, DynamoSecurityException
{
if (logger.isDebugEnabled())
logger.debug("CommunityManager.getMemberCommunities: " + caller.getName() + " getting community list for "
+ user.getName());
if (!(canGetMemberCommunityList(caller,user)))
{ // not permitted - bye!
logger.error("CommunityManager.getMemberCommunities: permission denied for " + caller.getName()
+ " to get community list for " + user.getName());
DynamoSecurityException dse = new DynamoSecurityException(CommunityManager.class,"CommunityMessages",
"auth.getCommList");
dse.setParameter(0,user.getName());
@ -351,6 +360,8 @@ public class CommunityManager
public synchronized VeniceCommunity getCommunity(int cid) throws DatabaseException
{
if (logger.isDebugEnabled())
logger.debug("CommunityManager.getCommunity(" + cid + ")");
Integer key = new Integer(cid);
CommunityImpl rc = (CommunityImpl)(m_id_to_comm.get(key));
if (rc==null)

View File

@ -29,3 +29,5 @@ auth.setName=You are not authorized to change the name of community "{0}."
auth.setAlias=You are not authorized to change the alias of community "{0}."
auth.grantAccess=You are not authorized to grant access to community "{0}."
auth.revokeAccess=You are not authorized to revoke access grants in community "{0}."
join.disallowed=You are not permitted to join community "{0}."
join.authFail=Unable to authenticate to community "{0}"; cannot join.

View File

@ -71,4 +71,13 @@ abstract class CommunityOps extends OpsBase
abstract Object getJoinRequirement(int cid, int uid) throws DatabaseException;
abstract Object getJoinEntryNull(int cid, int uid) throws DatabaseException;
abstract Object getJoinEntry(int cid, int uid, int auth_nsid, String auth_name, String source_data)
throws DatabaseException;
abstract String getAuthData(int cid, int ugid, boolean is_group) throws DatabaseException;
abstract void deleteSingleUseAuthData(int cid, int ugid, boolean is_group) throws DatabaseException;
} // end class CommunityOps

View File

@ -811,4 +811,204 @@ class CommunityOps_mysql extends CommunityOps
} // end getJoinRequirement
Object getJoinEntryNull(int cid, int uid) throws DatabaseException
{
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{ // get a connection
conn = getConnection();
// try looking for a user-level entry first
stmt = conn.prepareStatement("SELECT single_use FROM commaccess WHERE cid = ? AND ugid = ? AND is_group = 0 "
+ "AND auth_nsid IS NULL AND auth_name IS NULL;");
stmt.setInt(1,cid);
stmt.setInt(2,uid);
rs = stmt.executeQuery();
if (rs.next())
return Boolean.TRUE;
SQLUtils.shutdown(rs); // reset for next statement
rs = null;
SQLUtils.shutdown(stmt);
// Now look for a group matching the access for this user with no authenticator. Favor smaller groups
// over larger ones.
stmt = conn.prepareStatement("SELECT a.ugid, COUNT(g2.uid) AS gsize FROM commaccess a, groupmembers g, "
+ "groupmembers g2 WHERE a.cid = ? AND a.ugid = g.gid AND g.uid = ? "
+ "AND a.is_group = 1 AND a.auth_nsid IS NULL AND a.auth_name IS NULL "
+ "AND g2.gid = a.ugid GROUP BY g2.gid ORDER BY gsize;");
stmt.setInt(1,cid);
stmt.setInt(2,uid);
rs = stmt.executeQuery();
if (rs.next())
return new Integer(rs.getInt(1));
} // end try
catch (SQLException e)
{ // translate to a general DatabaseException
throw generalException(e);
} // end catch
finally
{ // shut everything down
SQLUtils.shutdown(rs);
SQLUtils.shutdown(stmt);
SQLUtils.shutdown(conn);
} // end finally
return null; // nothing else found...
} // end getJoinEntryNull
Object getJoinEntry(int cid, int uid, int auth_nsid, String auth_name, String source_data) throws DatabaseException
{
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{ // get a connection
conn = getConnection();
// try looking for a user-level entry first
stmt = conn.prepareStatement("SELECT single_use FROM commaccess WHERE cid = ? AND ugid = ? AND is_group = 0 "
+ "AND auth_nsid = ? AND auth_name = ? AND source_data = ?;");
stmt.setInt(1,cid);
stmt.setInt(2,uid);
stmt.setInt(3,auth_nsid);
stmt.setString(4,auth_name);
stmt.setString(5,source_data);
rs = stmt.executeQuery();
if (rs.next())
return Boolean.TRUE;
SQLUtils.shutdown(rs); // reset for next statement
rs = null;
SQLUtils.shutdown(stmt);
// Now look for a group matching the access for this user with the specified authenticator. Favor smaller groups
// over larger ones.
stmt = conn.prepareStatement("SELECT a.ugid, COUNT(g2.uid) AS gsize FROM commaccess a, groupmembers g, "
+ "groupmembers g2 WHERE a.cid = ? AND a.ugid = g.gid AND g.uid = ? "
+ "AND a.is_group = 1 AND a.auth_nsid = ? AND a.auth_name = ? "
+ "AND a.source_data = ? AND g2.gid = a.ugid GROUP BY g2.gid ORDER BY gsize;");
stmt.setInt(1,cid);
stmt.setInt(2,uid);
stmt.setInt(3,auth_nsid);
stmt.setString(4,auth_name);
stmt.setString(5,source_data);
rs = stmt.executeQuery();
if (rs.next())
return new Integer(rs.getInt(1));
} // end try
catch (SQLException e)
{ // translate to a general DatabaseException
throw generalException(e);
} // end catch
finally
{ // shut everything down
SQLUtils.shutdown(rs);
SQLUtils.shutdown(stmt);
SQLUtils.shutdown(conn);
} // end finally
return null; // nothing else found...
} // end getJoinEntry
String getAuthData(int cid, int ugid, boolean is_group) throws DatabaseException
{
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try
{ // get a connection
conn = getConnection();
// create and execute the statement
stmt = conn.prepareStatement("SELECT auth_data FROM commaccess WHERE cid = ? AND ugid = ? AND is_group = ?;");
stmt.setInt(1,cid);
stmt.setInt(2,ugid);
stmt.setInt(3,(is_group ? 1 : 0));
rs = stmt.executeQuery();
if (rs.next())
return rs.getString(1);
else
return null;
} // end try
catch (SQLException e)
{ // translate to a general DatabaseException
throw generalException(e);
} // end catch
finally
{ // shut everything down
SQLUtils.shutdown(rs);
SQLUtils.shutdown(stmt);
SQLUtils.shutdown(conn);
} // end finally
} // end getAuthData
void deleteSingleUseAuthData(int cid, int ugid, boolean is_group) throws DatabaseException
{
Connection conn = null;
PreparedStatement stmt = null;
Statement stmt2 = null;
ResultSet rs = null;
try
{ // get a connection
conn = getConnection();
// lock the commaccess table
stmt2 = conn.createStatement();
stmt2.executeUpdate("LOCK TABLES commaccess WRITE;");
// see whether the auth data is single-use
stmt = conn.prepareStatement("SELECT single_use FROM commaccess WHERE cid = ? AND ugid = ? AND is_group = ?;");
stmt.setInt(1,cid);
stmt.setInt(2,ugid);
stmt.setInt(3,(is_group ? 1 : 0));
rs = stmt.executeQuery();
if (!(rs.next()))
return;
if (rs.getInt(1)==0)
return;
SQLUtils.shutdown(rs); // reset for next statement
rs = null;
SQLUtils.shutdown(stmt);
// Now delete the authentication data.
stmt = conn.prepareStatement("DELETE FROM commaccess WHERE cid = ? AND ugid = ? AND is_group = ?;");
stmt.setInt(1,cid);
stmt.setInt(2,ugid);
stmt.setInt(3,(is_group ? 1 : 0));
stmt.executeUpdate();
} // end try
catch (SQLException e)
{ // translate to a general DatabaseException
throw generalException(e);
} // end catch
finally
{ // shut everything down
MySQLUtils.unlockTables(conn);
SQLUtils.shutdown(rs);
SQLUtils.shutdown(stmt);
SQLUtils.shutdown(stmt2);
SQLUtils.shutdown(conn);
} // end finally
} // end deleteSingleUseAuthData
} // end class CommunityOps_mysql

View File

@ -590,6 +590,19 @@ abstract class CommunityProxy implements VeniceCommunity, DynamicWrapper
} // end getJoinRequirement
public boolean join(DynamoUser joiner, String auth_namespace, String auth_name, String source_info,
String auth_info) throws DatabaseException, DynamoSecurityException
{
return getRealCommunity().join(joiner,auth_namespace,auth_name,source_info,auth_info);
} // end join
public boolean join(DynamoUser joiner) throws DatabaseException, DynamoSecurityException
{
return this.join(joiner,null,null,null,null);
} // end join
/*--------------------------------------------------------------------------------
* Implementations from interface DynamicWrapper
*--------------------------------------------------------------------------------

View File

@ -299,11 +299,16 @@ public interface VeniceCommunity extends NamedObject, SecureObjectStore
* community.</LI>
* </UL>
*
* @param joiner The user to test atainst the current community.
* @param joiner The user to test against the current community.
* @return See above.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the authenticator
* information for this user.
*/
public Object getJoinRequirement(DynamoUser joiner) throws DatabaseException;
public boolean join(DynamoUser joiner, String auth_namespace, String auth_name, String source_info,
String auth_info) throws DatabaseException, DynamoSecurityException;
public boolean join(DynamoUser joiner) throws DatabaseException, DynamoSecurityException;
} // end interface VeniceCommunity

View File

@ -147,4 +147,12 @@ public class LibraryVeniceCast
} // end toSideboxDescriptor
public final VeniceCommunity toVeniceCommunity(Object obj)
{
if (obj instanceof VeniceCommunity)
return (VeniceCommunity)obj;
throw new ClassCastException("LibraryVeniceCast.toVeniceCommunity: invalid cast");
} // end toVeniceCommunity
} // end class LibraryVeniceCast

View File

@ -15,6 +15,7 @@
// Contributor(s):
importPackage(java.lang);
importPackage(java.util);
importClass(Packages.com.silverwrist.dynamo.Namespaces);
importClass(Packages.com.silverwrist.dynamo.UserInfoNamespace);
importPackage(Packages.com.silverwrist.dynamo.dialog);
@ -22,7 +23,9 @@ importPackage(Packages.com.silverwrist.dynamo.iface);
importPackage(Packages.com.silverwrist.dynamo.mail);
importPackage(Packages.com.silverwrist.dynamo.util);
importClass(Packages.com.silverwrist.venice.VeniceNamespaces);
importPackage(Packages.com.silverwrist.venice.community);
importPackage(Packages.com.silverwrist.venice.frame);
importPackage(Packages.com.silverwrist.venice.iface);
importPackage(Packages.com.silverwrist.venice.session);
req = bsf.lookupBean("request");
@ -132,13 +135,33 @@ if (op=="create")
dynamo.scriptReturn(new ErrorBox("Internal Error","Unable to copy settings to new user.",target));
// Add this user to the "all users" group.
srm = cast.querySecurityReferenceMonitor(req_help.getRequestObject(Namespaces.DYNAMO_OBJECT_NAMESPACE,
"srm"));
srm = cast.querySecurityReferenceMonitor(req_help.getRequestObject(Namespaces.DYNAMO_OBJECT_NAMESPACE,"srm"));
srm.getAllUsersGroup().addMember(new_user);
// Write an audit message indicating the new user was created.
audit.write(req,new_user,VeniceNamespaces.USER_EVENT_NAMESPACE,"user.created");
// Get all communities that the anonymous user is a member of and add the new user as a member of
// any community that they can join as a result.
commsvc = vcast.queryCommunityService(req_help.getRequestObject(Namespaces.DYNAMO_OBJECT_NAMESPACE,"communities"));
anon_list = commsvc.getMemberCommunities(new_user,umgmt.getAnonymousUser());
it = anon_list.iterator();
while (it.hasNext())
{ // get each community and its join requirements
comm = vcast.toVeniceCommunity(it.next());
logger.debug("Checking community: " + comm.name);
jreq = comm.getJoinRequirement(new_user);
if (cast.isBooleanTrue(jreq))
{ // OK, join this community
logger.debug("OK to join community: " + comm.name);
if (comm.join(new_user))
{
}
} // end if
} // end while
// Generate an E-mail confirmation number and add it to the user properties.
confnum = vlib.randomConfirmationNumber();
new_user.setObject(new_user,VeniceNamespaces.USER_SETTINGS_NAMESPACE,"confirmation.number",
@ -154,8 +177,7 @@ if (op=="create")
msg = mailprov.createSystemMessage(req);
msg.addRecipient(MailMessage.RECIP_TO,new_user.getEMailAddress());
globals = vcast.getGlobalPropertiesStore(req);
msg.setSubject(globals.getObject(VeniceNamespaces.MAIL_MESSAGES_NAMESPACE,
"confirm.message.title").toString());
msg.setSubject(globals.getObject(VeniceNamespaces.MAIL_MESSAGES_NAMESPACE,"confirm.message.title").toString());
blocks = vcast.getGlobalBlocksStore(req);
msg.setText(blocks.getObject(VeniceNamespaces.MAIL_MESSAGES_NAMESPACE,"confirm.message").toString());
msg.setVariable("username",new_user.getName());
@ -163,8 +185,7 @@ if (op=="create")
msg.send();
// Write an audit message.
audit.write(req,new_user,VeniceNamespaces.USER_EVENT_NAMESPACE,"send.confirm.email",
new_user.getEMailAddress());
audit.write(req,new_user,VeniceNamespaces.USER_EVENT_NAMESPACE,"send.confirm.email",new_user.getEMailAddress());
// Now bounce us to the "verification" dialog.
dynamo.scriptOutput(new Redirect("SERVLET","verify_email.js.vs?tgt=" + stringutils.encodeURL(target)));

View File

@ -14,12 +14,16 @@
//
// Contributor(s):
importPackage(java.lang);
importPackage(java.util);
importClass(Packages.com.silverwrist.dynamo.Namespaces);
importPackage(Packages.com.silverwrist.dynamo.iface);
importPackage(Packages.com.silverwrist.dynamo.mail);
importPackage(Packages.com.silverwrist.dynamo.security);
importPackage(Packages.com.silverwrist.dynamo.util);
importClass(Packages.com.silverwrist.venice.VeniceNamespaces);
importPackage(Packages.com.silverwrist.venice.community);
importPackage(Packages.com.silverwrist.venice.iface);
req = bsf.lookupBean("request");
req_help = bsf.lookupBean("request_help");
@ -140,6 +144,26 @@ if (op=="ok")
"srm"));
srm.getVerifiedUsersGroup().addMember(user);
// Get all communities that the anonymous user is a member of and add the new user as a member of
// any community that they can join as a result.
umgmt = cast.queryUserManagement(req_help.getRequestObject(Namespaces.DYNAMO_OBJECT_NAMESPACE,"users"));
commsvc = vcast.queryCommunityService(req_help.getRequestObject(Namespaces.DYNAMO_OBJECT_NAMESPACE,"communities"));
anon_list = commsvc.getMemberCommunities(user,umgmt.getAnonymousUser());
it = anon_list.iterator();
while (it.hasNext())
{ // get each community and its join requirements
comm = vcast.toVeniceCommunity(it.next());
jreq = comm.getJoinRequirement(user);
if (cast.isBooleanTrue(jreq))
{ // OK, join the community
if (comm.join(user))
{
}
} // end if
} // end while
// and that does it - bounce us on to whereever we were going
dynamo.scriptOutput(new Redirect("SERVLET",target));