public Yield GetGroupUsers(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.READ); GroupBE group = GetGroupFromUrl(); DreamMessage responseMsg = null; uint totalCount; uint queryCount; var usersInGroup = UserBL.GetUsersByQuery(context, group.Id, out totalCount, out queryCount); XDoc ret = new XDoc("users"); ret.Attr("count", usersInGroup.Count()); ret.Attr("querycount", queryCount); ret.Attr("totalcount", totalCount); ret.Attr("href", DekiContext.Current.ApiUri.At("groups", group.Id.ToString(), "users")); foreach (UserBE member in usersInGroup) { ret.Add(UserBL.GetUserXml(member, null, Utils.ShowPrivateUserInfo(member))); } responseMsg = DreamMessage.Ok(ret); response.Return(responseMsg); yield break; }
public static XDoc GetGroupXmlVerbose(GroupBE group, string relation) { XDoc groupXml = GetGroupXml(group, relation); ServiceBE authService = ServiceBL.GetServiceById(group.ServiceId); if (authService != null) { groupXml.Add(ServiceBL.GetServiceXml(authService, "authentication")); } groupXml.Start("users"); if (group.UserIdsList != null) { groupXml.Attr("count", group.UserIdsList.Length); } groupXml.Attr("href", DekiContext.Current.ApiUri.At("groups", group.Id.ToString(), "users")); groupXml.End(); //Permissions for the group RoleBE role = PermissionsBL.GetRoleById(group.RoleId); groupXml.Add(PermissionsBL.GetRoleXml(role, "group")); return(groupXml); }
public static GroupBE SetGroupMembers(GroupBE group, XDoc userList) { UserBE[] members = ProcessGroupMemberInput(group, userList); DbUtils.CurrentSession.GroupMembers_UpdateUsersInGroup(group.Id, members.Select(e => e.ID).ToList(), DateTime.UtcNow); // reload the group to ensure group members are set return(GetGroupById(group.Id)); }
public Yield DeleteGroup(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); GroupBE group = GetGroupFromUrl(); DbUtils.CurrentSession.Groups_Delete(group.Id); response.Return(DreamMessage.Ok()); yield break; }
public Yield PostGroupUsers(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); GroupBE group = GetGroupFromUrl(); group = GroupBL.AddGroupMembers(group, request.ToDocument()); response.Return(DreamMessage.Ok(GroupBL.GetGroupXmlVerbose(group, null))); yield break; }
public Yield GetGroup(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.READ); GroupBE group = GetGroupFromUrl(); DreamMessage responseMsg = DreamMessage.Ok(GroupBL.GetGroupXmlVerbose(group, null)); response.Return(responseMsg); yield break; }
public static XDoc GetGroupXml(GroupBE group, string relation) { XDoc groupXml = new XDoc(string.IsNullOrEmpty(relation) ? "group" : "group." + relation); groupXml.Attr("id", group.Id); groupXml.Attr("href", DekiContext.Current.ApiUri.At("groups", group.Id.ToString())); groupXml.Start("groupname").Value(group.Name).End(); return(groupXml); }
public Yield PostGroup(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); DreamMessage responseMsg = null; GroupBE group = GroupBL.PostGroupFromXml(request.ToDocument(), null, context.GetParam("authusername", null), context.GetParam("authpassword", null)); responseMsg = DreamMessage.Ok(GroupBL.GetGroupXmlVerbose(group, null)); response.Return(responseMsg); yield break; }
public Yield DeleteGroupUser(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); GroupBE group = GetGroupFromUrl(); UserBE user = GetUserFromUrlMustExist(); group = GroupBL.RemoveGroupMember(group, user); response.Return(DreamMessage.Ok(GroupBL.GetGroupXmlVerbose(group, null))); yield break; }
private IList <GroupBE> Groups_GetInternal(string where, string functionDescription, bool lookupCount, uint?limit, uint?offset, out uint totalCount, out uint queryCount) { totalCount = queryCount = 0; uint totalCountTemp = 0, queryCountTemp = 0; List <GroupBE> groups = new List <GroupBE>(); string totalCountQuery = lookupCount ? "select count(*) as totalcount from groups" : string.Empty; string queryCountQuery = lookupCount ? "select count(*) as querycount from groups " + where : string.Empty; string limitOffsetQuery = string.Empty; if (limit != null || offset != null) { limitOffsetQuery = string.Format("limit {0} offset {1}", limit ?? int.MaxValue, offset ?? 0); } string query = string.Format(@" /* GroupDA::{0} */ SET group_concat_max_len = @@max_allowed_packet; select groups.*, ( select cast(group_concat( user_groups.user_id, '') as char) from user_groups join users on users.user_id = user_groups.user_id where user_groups.group_id = groups.group_id group by user_groups.group_id ) as group_userids from groups {1} {2}; {3}; {4}; ", functionDescription, where.TrimEnd(new char[] { ';' }), limitOffsetQuery, totalCountQuery, queryCountQuery); Catalog.NewQuery(query) .Execute(delegate(IDataReader dr) { while (dr.Read()) { GroupBE group = Groups_Populate(dr); groups.Add(group); } if (dr.NextResult() && dr.Read()) { totalCountTemp = DbUtils.Convert.To <uint>(dr["totalcount"], 0); } if (dr.NextResult() && dr.Read()) { queryCountTemp = DbUtils.Convert.To <uint>(dr["querycount"], 0); } }); totalCount = totalCountTemp; queryCount = queryCountTemp; return(groups); }
public void Groups_Update(GroupBE group) { Catalog.NewQuery(@" /* Groups_Update */ UPDATE groups set group_role_id = ?ROLEID, group_name = ?NAME where group_id = ?GROUPID;") .With("GROUPID", group.Id) .With("ROLEID", group.RoleId) .With("NAME", group.Name) .Execute(); }
private GroupBE Groups_Populate(IDataReader dr) { GroupBE group = new GroupBE(); group.CreatorUserId = dr.Read <uint>("group_creator_user_id"); group.Id = dr.Read <uint>("group_id"); group.Name = dr.Read <string>("group_name"); group.RoleId = dr.Read <uint>("group_role_id"); group.ServiceId = dr.Read <uint>("group_service_id"); group.TimeStamp = dr.Read <DateTime>("group_last_edit"); group.UserIds = dr.Read <string>("group_userids"); return(group); }
public uint Groups_Insert(GroupBE group) { uint groupId = Catalog.NewQuery(@" /* Groups_Insert */ insert IGNORE into `groups` (`group_name`, `group_role_id`, `group_service_id`, `group_creator_user_id`, `group_last_edit`) values (?NAME, ?ROLEID, ?SERVICEID, ?CREATORUSERID, ?TIMESTAMP); select LAST_INSERT_ID();") .With("NAME", group.Name) .With("ROLEID", group.RoleId) .With("SERVICEID", group.ServiceId) .With("CREATORUSERID", group.CreatorUserId) .With("TIMESTAMP", group.TimeStamp) .ReadAsUInt() ?? 0; return(groupId); }
public static GroupBE AddGroupMembers(GroupBE group, XDoc userList) { UserBE[] newMembers = ProcessGroupMemberInput(group, userList); if (ArrayUtil.IsNullOrEmpty(newMembers)) { return(group); } var members = GetMemberUsers(group).ToList(); members.AddRange(newMembers); DbUtils.CurrentSession.GroupMembers_UpdateUsersInGroup(group.Id, members.Select(e => e.ID).ToList(), DateTime.UtcNow); return(GetGroupById(group.Id)); }
public static GroupBE RemoveGroupMember(GroupBE group, UserBE user) { List <UserBE> members = new List <UserBE>(); foreach (UserBE u in GetMemberUsers(group)) { if (u.ID != user.ID) { members.Add(u); } } DbUtils.CurrentSession.GroupMembers_UpdateUsersInGroup(group.Id, members.Select(e => e.ID).ToList(), DateTime.UtcNow); return(GetGroupById(group.Id)); }
private static UserBE[] ProcessGroupMemberInput(GroupBE group, XDoc userList) { if (!userList.HasName("users")) { throw new GroupExpectedUserRootNodeInvalidArgumentException(); } ServiceBE service = ServiceBL.GetServiceById(group.ServiceId); if (service == null) { throw new GroupServiceNotFoundFatalException(group.ServiceId, group.Name); } //Changing members of an external group is not supported. You may modify members in the external provider instead. if (!ServiceBL.IsLocalAuthService(service)) { throw new ExternalGroupMemberInvalidOperationException(); } UserBE[] members = ReadUserListXml(userList); ValidateGroupMemberList(service, members); return(members); }
private GroupBE Groups_Populate(IDataReader dr) { GroupBE group = new GroupBE(); group.CreatorUserId = dr.Read<uint>("group_creator_user_id"); group.Id = dr.Read<uint>("group_id"); group.Name = dr.Read<string>("group_name"); group.RoleId = dr.Read<uint>("group_role_id"); group.ServiceId = dr.Read<uint>("group_service_id"); group.TimeStamp = dr.Read<DateTime>("group_last_edit"); group.UserIds = dr.Read<string>("group_userids"); return group; }
public void Groups_Update(GroupBE group) { Catalog.NewQuery(@" /* Groups_Update */ UPDATE groups set group_role_id = ?ROLEID, group_name = ?NAME where group_id = ?GROUPID;") .With("GROUPID", group.Id) .With("ROLEID", group.RoleId) .With("NAME", group.Name) .Execute(); }
public uint Groups_Insert(GroupBE group) { uint groupId = Catalog.NewQuery(@" /* Groups_Insert */ insert IGNORE into `groups` (`group_name`, `group_role_id`, `group_service_id`, `group_creator_user_id`, `group_last_edit`) values (?NAME, ?ROLEID, ?SERVICEID, ?CREATORUSERID, ?TIMESTAMP); select LAST_INSERT_ID();") .With("NAME", group.Name) .With("ROLEID", group.RoleId) .With("SERVICEID", group.ServiceId) .With("CREATORUSERID", group.CreatorUserId) .With("TIMESTAMP", group.TimeStamp) .ReadAsUInt() ?? 0; return groupId; }
private static IEnumerable <UserBE> GetMemberUsers(GroupBE group) { return((group.UserIdsList == null || !group.UserIdsList.Any()) ? new UserBE[0] : DbUtils.CurrentSession.Users_GetByIds(group.UserIdsList)); }
public static GroupBE PostGroupFromXml(XDoc groupDoc, GroupBE groupToProcess, string externalusername, string externalpassword) { GroupBE group = null; string groupName = string.Empty; ServiceBE groupService = null; RoleBE groupRole = null; UserBE[] groupMembers = null; uint? groupId = null; ParseGroupXml(groupDoc, out groupId, out groupName, out groupService, out groupRole, out groupMembers); //Create new group if (groupToProcess == null && (groupId == null || groupId == 0)) { if (groupService == null) { groupService = ServiceBL.RetrieveLocalAuthService(); } //External groups should be confirmed with the auth provider if (groupService != null && !ServiceBL.IsLocalAuthService(groupService)) { //username+password from request query params are used here group = ExternalServiceSA.BuildGroupFromAuthService(groupService, groupToProcess, groupName, externalusername, externalpassword); if (group == null) { throw new ExternalGroupNotFoundException(groupName); } } //Does this group already exist? GroupBE tempGroup = GetGroupByName(groupName); if (tempGroup != null) { throw new GroupExistsWithServiceConflictException(groupName, tempGroup.ServiceId); } ValidateGroupMemberList(groupService, groupMembers); // Insert the group GroupBE newGroup = new GroupBE(); newGroup.Name = groupName; newGroup.RoleId = groupRole.ID; newGroup.ServiceId = groupService.Id; newGroup.CreatorUserId = DekiContext.Current.User.ID; newGroup.TimeStamp = DateTime.UtcNow; uint newGroupId = DbUtils.CurrentSession.Groups_Insert(newGroup); if (newGroupId == 0) { group = null; } else { DbUtils.CurrentSession.GroupMembers_UpdateUsersInGroup(newGroupId, groupMembers.Select(e => e.ID).ToList(), newGroup.TimeStamp); // reload the group to ensure group members are set group = GetGroupById(newGroupId); } } //Edit existing group else { if (groupId != null) { groupToProcess = GetGroupById(groupId.Value); } if (groupToProcess == null) { throw new GroupIdNotFoundException(groupId); } group = groupToProcess; //Change the role? if (group.RoleId != groupRole.ID) { group.RoleId = groupRole.ID; } //Rename the group? if (group.Name != groupName && !string.IsNullOrEmpty(groupName)) { GroupBE tempGroup = GetGroupByName(groupName); if (tempGroup != null) { throw new GroupExistsWithServiceConflictException(groupName, tempGroup.ServiceId); } if (!ServiceBL.IsLocalAuthService(group.ServiceId)) { //TODO MaxM: allow renaming of external groups throw new ExternalGroupRenameNotImplementedException(); } //Set the new name of the group. group.Name = groupName; } DbUtils.CurrentSession.Groups_Update(group); //TODO (MaxM): Update group list as well? group = GetGroupById(group.Id); } if (group == null) { throw new GroupCreateUpdateFatalException(); } return(group); }
public static UserBE BuildUserFromAuthService(ServiceBE serviceInfo, UserBE knownUser, string usernameToBuild, bool bypassAuthentication, string authusername, string password, out List <GroupBE> externalGroups) { externalGroups = null; if (serviceInfo == null || string.IsNullOrEmpty(usernameToBuild)) { return(null); } //Dont perform external lookup for disabled users if (knownUser != null && !knownUser.UserActive) { return(knownUser); } var errMsg = DekiResources.UNABLE_TO_AUTH_WITH_SERVICE(serviceInfo.Type, serviceInfo.SID, serviceInfo.Uri); if (knownUser != null && !string.IsNullOrEmpty(knownUser.ExternalName)) { usernameToBuild = knownUser.ExternalName; } UserBE ret = null; DreamMessage response = null; if (serviceInfo.Uri == null) { throw new ExternalServiceNotStartedFatalException(serviceInfo.Type, serviceInfo.SID); } try { Plug dekiExternalAuthPlug; //bypassAuthentication is used when you only need user details but not to necessarily authenticate if (bypassAuthentication) { //An external auth service's GET: user/{username} does not necessarily require authentication to lookup users but it may. It's up to the service //to decide if anon requests are allowed. dekiExternalAuthPlug = Plug.New(serviceInfo.Uri).At(USER_INFO).At(XUri.Encode(usernameToBuild)); } else { //Credentials are always needed for GET: authenticate. The user details of the auth'd user is returned with same format as GET: user/{username} dekiExternalAuthPlug = Plug.New(serviceInfo.Uri).At(AUTHENTICATE_PATH); } //Always include credentials with the request if they're supplied if (!string.IsNullOrEmpty(authusername)) { dekiExternalAuthPlug = dekiExternalAuthPlug.WithCredentials(authusername, password ?? string.Empty); } response = dekiExternalAuthPlug.GetAsync().Wait(); } catch (Exception x) { throw new ExternalServiceResponseException(errMsg, DreamMessage.InternalError(x)); } if (response.IsSuccessful) { XDoc userXml = response.ToDocument(); if (userXml == null || userXml.IsEmpty) { throw new ExternalAuthResponseFatalException(); } string nameFromAuthProvider = userXml["@name"].Contents; if (!nameFromAuthProvider.EqualsInvariantIgnoreCase(usernameToBuild)) { throw new ExternalServiceUnexpecteUsernameFatalException(userXml["@name"].AsText, usernameToBuild); } ret = knownUser ?? new UserBE(); ret.Email = string.IsNullOrEmpty(userXml["email"].AsText) ? (ret.Email ?? string.Empty) : userXml["email"].AsText; //Build the realname (exposed as 'fullname' in user xml) by saving it as '{firstname} {lastname}' string externalFirstName = userXml["firstname"].AsText ?? string.Empty; string externalLastName = userXml["lastname"].AsText ?? string.Empty; string separator = externalLastName.Length > 0 && externalFirstName.Length > 0 ? ", " : string.Empty; // NOTE (maxm): Fullname sync is disabled for now. Refer to bug 7855 #if !DISABLE_REAL_NAME_SYNCHRONIZATION ret.RealName = string.Format("{0}{1}{2}", externalLastName, separator, externalFirstName); #endif ret.ServiceId = serviceInfo.Id; ret.Touched = DateTime.UtcNow; ret.ExternalName = string.IsNullOrEmpty(ret.ExternalName) ? nameFromAuthProvider : ret.ExternalName; ret.Name = string.IsNullOrEmpty(ret.Name) ? nameFromAuthProvider : ret.Name; //For new users, the name must be normalized and unique if (ret.ID == 0) { string nameFromExternalName = string.Empty; //Allow using a displayname from an external provider only for new accounts if (!userXml["@displayname"].IsEmpty) { nameFromExternalName = userXml["@displayname"].AsText; } else { nameFromExternalName = ret.ExternalName; } ret.Name = UserBL.NormalizeExternalNameToWikiUsername(nameFromExternalName); } //Build group objects out of the user's group membership list externalGroups = new List <GroupBE>(); IList <GroupBE> userGroups = DbUtils.CurrentSession.Groups_GetByUser(ret.ID); //Preserve local groups for existing users if (ret.ID != 0 && userGroups != null) { foreach (GroupBE g in userGroups) { if (ServiceBL.IsLocalAuthService(g.ServiceId)) { externalGroups.Add(g); } } } foreach (XDoc group in userXml["groups/group"]) { GroupBE g = new GroupBE(); g.Name = group["@name"].AsText; g.ServiceId = serviceInfo.Id; if (!string.IsNullOrEmpty(g.Name)) { externalGroups.Add(g); } } } else { switch (response.Status) { case DreamStatus.Unauthorized: if (bypassAuthentication) { DekiContext.Current.Instance.Log.Warn(string.Format("Attempted to lookup user info on auth provider '{0}' but failed since it required credentials", serviceInfo.Id)); } throw new ExternalServiceAuthenticationDeniedException(DekiWikiService.AUTHREALM, serviceInfo.Description); default: throw new ExternalServiceResponseException(errMsg, response); } } return(ret); }
public static GroupBE BuildGroupFromAuthService(ServiceBE serviceInfo, GroupBE knownGroup, string groupNameToBuild, string authusername, string password) { if (serviceInfo == null || string.IsNullOrEmpty(groupNameToBuild)) { return(null); } GroupBE ret = null; DreamMessage response = null; if (serviceInfo.Uri == null) { throw new ExternalServiceNotStartedFatalException(serviceInfo.Type, serviceInfo.SID); } var errMsg = DekiResources.GROUP_DETAILS_LOOKUP_FAILED(groupNameToBuild); try { Plug dekiExternalAuthPlug = Plug.New(serviceInfo.Uri).At(GROUP_INFO).At(XUri.Encode(groupNameToBuild)); //Always include credentials with the request if they're supplied if (!string.IsNullOrEmpty(authusername)) { dekiExternalAuthPlug = dekiExternalAuthPlug.WithCredentials(authusername, password ?? string.Empty); } response = dekiExternalAuthPlug.GetAsync().Wait(); } catch (Exception x) { throw new ExternalServiceResponseException(errMsg, DreamMessage.InternalError(x)); } if (response.IsSuccessful) { XDoc groupXml = response.ToDocument(); if (groupXml.HasName("group") && groupXml["@name"].Contents.EqualsInvariant(groupNameToBuild)) { if (knownGroup == null) { ret = new GroupBE(); } else { ret = knownGroup; } ret.Name = string.IsNullOrEmpty(ret.Name) ? groupNameToBuild : ret.Name; ret.ServiceId = serviceInfo.Id; } //TODO (MaxM): Consider looking up existing wiki users and associating them here. } else { switch (response.Status) { case DreamStatus.Unauthorized: throw new ExternalServiceAuthenticationDeniedException(DekiWikiService.AUTHREALM, serviceInfo.Description); case DreamStatus.InternalError: case DreamStatus.Forbidden: default: throw new ExternalServiceResponseException(errMsg, response); } } return(ret); }