Example #1
0
        //--- 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);
        }
Example #2
0
        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);
        }
Example #3
0
        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;
        }
Example #4
0
        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;
        }
Example #5
0
        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;
        }
Example #6
0
        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;
        }
Example #7
0
        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);
        }
Example #8
0
 public void Groups_Update(GroupBE group) {
     Stopwatch sw = Stopwatch.StartNew();
     _next.Groups_Update(group);
     LogQuery(CATEGORY_GROUPS, "Groups_Update", sw, "group", group);
 }
Example #9
0
 private static IEnumerable<UserBE> GetMemberUsers(GroupBE group) {
     return (group.UserIdsList == null || !group.UserIdsList.Any())
         ? new UserBE[0]
         : DbUtils.CurrentSession.Users_GetByIds(group.UserIdsList);
 }
Example #10
0
        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);
        }
Example #11
0
        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;
        }
Example #12
0
 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;
 }
Example #13
0
 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;
 }
Example #14
0
 //--- 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;
        }
Example #16
0
        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;
        }
Example #18
0
 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;
 }