//--- Methods --- public virtual GroupBE Copy() { GroupBE group = new GroupBE(); group.CreatorUserId = CreatorUserId; group.Id = Id; group.Name = Name; group.RoleId = RoleId; group.ServiceId = ServiceId; group.TimeStamp = TimeStamp; group.UserIds = UserIds; return(group); }
public static void UpdateUsersGroups(UserBE user, GroupBE[] groups) { if(user == null || groups == null) return; IList<GroupBE> groupsWithIds = DbUtils.CurrentSession.Groups_GetByNames(groups.Select(e => e.Name).ToList()); DbUtils.CurrentSession.GroupMembers_UpdateGroupsForUser(user.ID, groupsWithIds.Select(e => e.Id).ToList()); UpdateUser(user); }
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 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 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; }
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; }
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); }
public void Groups_Update(GroupBE group) { Stopwatch sw = Stopwatch.StartNew(); _next.Groups_Update(group); LogQuery(CATEGORY_GROUPS, "Groups_Update", sw, "group", group); }
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 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); }
private static UserBE[] ProcessGroupMemberInput(GroupBE group, XDoc userList) { if(!userList.HasName("users")) { throw new DreamBadRequestException(DekiResources.EXPECTED_ROOT_NODE_USERS); } ServiceBE service = ServiceBL.GetServiceById(group.ServiceId); if(service == null) { throw new DreamInternalErrorException(string.Format("Could not find service with id '{0}' for group name '{1}'. ", 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 DreamBadRequestException(DekiResources.GROUP_EXTERNAL_CHANGE_MEMBERS); } UserBE[] members = ReadUserListXml(userList); ValidateGroupMemberList(service, members); return members; }
private static IList<UserBE> GetMemberUsers(GroupBE group) { IList<UserBE> memberUsers; if (ArrayUtil.IsNullOrEmpty(group.UserIdsList)) { memberUsers = new List<UserBE>(); } else { memberUsers = DbUtils.CurrentSession.Users_GetByIds(group.UserIdsList); } return memberUsers; }
internal Hashtable MakeGroupObject(GroupBE group) { var result = new Hashtable(StringComparer.OrdinalIgnoreCase); if(group != null) { result.Add("name", group.Name); result.Add("id", group.Id); } return result; }
//--- Methods --- public virtual GroupBE Copy() { GroupBE group = new GroupBE(); group.CreatorUserId = CreatorUserId; group.Id = Id; group.Name = Name; group.RoleId = RoleId; group.ServiceId = ServiceId; group.TimeStamp = TimeStamp; group.UserIds = UserIds; return group; }
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; string errMsg = string.Format(DekiResources.GROUP_DETAILS_LOOKUP_FAILED, groupNameToBuild); DreamMessage response = null; if (serviceInfo.Uri == null) throw new DreamAbortException(DreamMessage.InternalError(string.Format(DekiResources.SERVICE_NOT_STARTED, serviceInfo.Type.ToString(), serviceInfo.SID))); 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 DreamResponseException(DreamMessage.InternalError(x), errMsg); } if (response.IsSuccessful) { XDoc groupXml = response.ToDocument(); if(groupXml.HasName("group") && StringUtil.EqualsInvariant(groupXml["@name"].Contents, 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 DreamAbortException(DreamMessage.AccessDenied(DekiWikiService.AUTHREALM, string.Format(DekiResources.AUTHENTICATION_FAILED_FOR, serviceInfo.Description))); case DreamStatus.InternalError: case DreamStatus.Forbidden: default: throw new DreamAbortException(response, string.Format(DekiResources.GROUP_DETAILS_LOOKUP_FAILED, groupNameToBuild)); } } return ret; }
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 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; string errMsg = string.Format(DekiResources.UNABLE_TO_AUTH_WITH_SERVICE, serviceInfo.Type.ToString(), 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 DreamAbortException(DreamMessage.InternalError(string.Format(DekiResources.SERVICE_NOT_STARTED, serviceInfo.Type.ToString(), 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 DreamResponseException(DreamMessage.InternalError(x), errMsg); } if (response.IsSuccessful) { XDoc userXml = response.ToDocument(); if (userXml == null || userXml.IsEmpty) { throw new DreamInternalErrorException(string.Format("Empty or not well-formed XML returned from remote auth service: " + userXml.ToPrettyString())); } string nameFromAuthProvider = userXml["@name"].Contents; if (!StringUtil.EqualsInvariantIgnoreCase(nameFromAuthProvider, usernameToBuild)) { throw new DreamInternalErrorException(string.Format(DekiResources.UNEXPECTED_EXTERNAL_USERNAME, userXml["@name"].AsText, usernameToBuild)); } if (knownUser != null) ret = knownUser; else ret = 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 DreamAbortException(DreamMessage.AccessDenied(DekiWikiService.AUTHREALM, string.Format(DekiResources.AUTHENTICATION_FAILED_FOR, serviceInfo.Description))); case DreamStatus.InternalError: case DreamStatus.Forbidden: default: throw new DreamAbortException(response, errMsg); } } return ret; }
public uint Groups_Insert(GroupBE group) { Stopwatch sw = Stopwatch.StartNew(); var ret = _next.Groups_Insert(group); LogQuery(CATEGORY_GROUPS, "Groups_Insert", sw, "group", group); return ret; }