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); }
private static void ParseGroupXml(XDoc groupDoc, out uint?id, out string name, out ServiceBE authService, out RoleBE role, out UserBE[] userList) { name = groupDoc["groupname"].AsText ?? groupDoc["name"].AsText; string authserviceidstr = groupDoc["service.authentication/@id"].AsText; string rolestr = groupDoc["permissions.group/role"].AsText; authService = null; role = null; id = null; if (!groupDoc["@id"].IsEmpty) { uint id_temp; if (!uint.TryParse(groupDoc["@id"].Contents, out id_temp)) { throw new GroupIdAttributeInvalidArgumentException(); } id = id_temp; } if (!string.IsNullOrEmpty(authserviceidstr)) { uint serviceid; if (!uint.TryParse(authserviceidstr, out serviceid)) { throw new ServiceAuthIdAttrInvalidArgumentException(); } authService = ServiceBL.GetServiceById(serviceid); if (authService == null) { throw new ServiceDoesNotExistInvalidArgumentException(serviceid); } } if (!string.IsNullOrEmpty(rolestr)) { role = PermissionsBL.GetRoleByName(rolestr); if (role == null) { throw new RoleDoesNotExistInvalidArgumentException(rolestr); } } else { role = PermissionsBL.RetrieveDefaultRoleForNewAccounts(); } if (!groupDoc["users"].IsEmpty) { userList = ReadUserListXml(groupDoc["users"]); } else { userList = new UserBE[] { } }; }
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); }
//--- Class Methods --- public static UserBE Authenticate(DreamContext context, DreamMessage request, uint serviceId, bool autoCreateExternalUser, bool allowAnon, out bool altPassword) { UserBE user = null; altPassword = false; // Case 1: username/fullname, password, provider (login window) // 1. Validate & retrieve fullname using credentials // Failed -> return null // 2. Populate user object // A. Populates user info // B. Populates group info in user object // 3. Does fullname exist? // Yes -> Update user (email, fullname, ...) // No -> Create user // 4. Update Group information // 5. return user object // // Case 2: fullname, password (http, api, ...) // 1. Lookup full name, exist? // Yes -> return user // No -> return null // // Case 3: auth-token (header auth) // 0. Valid auth token? // No -> return null // 1. Lookup user by name // Found -> return user // Else -> return null string userName = null; string password = null; UserBE userFromToken = null; ServiceBE authService = null; // Extract authtoken and impersonation authtoken from request. // AllowAnon is false when in GET/POST: users/authenticate or when ?authenticate=true. // Standard user authtokens are ignored when AllowAnon=false but impersonation tokens are accepted. bool impersonationOnly = !allowAnon; userFromToken = UserFromAuthTokenInRequest(context, impersonationOnly); if (userFromToken == null) { HttpUtil.GetAuthentication(context.Uri.ToUri(), request.Headers, out userName, out password); } // check if we need to retrieve authentication service information if (serviceId > 0) { authService = ServiceBL.GetServiceById(serviceId); if (authService == null) { throw new AuthServiceIdInvalidArgumentException(serviceId); } if (authService.Type != ServiceType.AUTH) { throw new AuthNotAnAuthServiceInvalidArgumentException(serviceId); } } // check if a username was provided if (!string.IsNullOrEmpty(userName)) { //Case 2: Given username + password if (authService == null) { //Assuming local user or existing external account user = DbUtils.CurrentSession.Users_GetByName(userName); if (user != null) { serviceId = user.ServiceId; authService = ServiceBL.GetServiceById(serviceId); } else { LoginAccessDenied(context, request, userName, null, password); } } if (authService == null) { throw new AuthServiceIdInvalidArgumentException(serviceId); } if (authService.Type != ServiceType.AUTH) { throw new AuthNotAnAuthServiceInvalidArgumentException(serviceId); } if (user == null) { //Performing auth on local account if (ServiceBL.IsLocalAuthService(authService)) { user = DbUtils.CurrentSession.Users_GetByName(userName); } else { //Performing external auth. Lookup by external user name user = DbUtils.CurrentSession.Users_GetByExternalName(userName, authService.Id); } if (user != null && user.ServiceId != authService.Id) { ServiceBE currentUsersAuthService = ServiceBL.GetServiceById(user.ServiceId); if (currentUsersAuthService != null) { throw new AuthLoginExternalUserConflictException(currentUsersAuthService.Description); } throw new LoginExternalUserUnknownConflictException(); } } //Local account in the db. if (user != null && ServiceBL.IsLocalAuthService(authService)) { //Validate password for local account or validate the apikey if (!IsValidAuthenticationForLocalUser(user, password, out altPassword)) { // try impersonation using the ApiKey if (string.IsNullOrEmpty(password) && PermissionsBL.ValidateRequestApiKey()) { DekiContext.Current.Instance.Log.InfoFormat("user '{0}' authenticated via apikey impersonation", userName); } else { LoginAccessDenied(context, request, userName, user.ID, password); } } } // User was not found in the db and not being asked to create it. if (user == null && !autoCreateExternalUser) { LoginAccessDenied(context, request, userName, null, password); } // Creating local account if apikey checks out and our authservice is local if (user == null && string.IsNullOrEmpty(password) && PermissionsBL.ValidateRequestApiKey() && ServiceBL.IsLocalAuthService(authService)) { XDoc newUserDoc = new XDoc("user") .Elem("username", userName); DreamMessage newUserResponse = DekiContext.Current.ApiPlug.At("users") .With("apikey", DreamContext.Current.GetParam("apikey", string.Empty)) .Post(newUserDoc); user = UserBL.GetUserById(newUserResponse.ToDocument()["/user/@id"].AsUInt ?? 0); if (user != null && !string.IsNullOrEmpty(password)) { user = UserBL.SetPassword(user, password, false); } } // Got an external account // Passing in the user object from db if it was found. List <GroupBE> externalGroups = null; if (!ServiceBL.IsLocalAuthService(authService)) { bool bypassAuthentication = false; string externalName; if (user == null || string.IsNullOrEmpty(user.ExternalName)) { externalName = userName; } else { externalName = user.ExternalName; } // If apikey is valid, try to bypass auth with the external provider // and only lookup user/group details. if (string.IsNullOrEmpty(password) && PermissionsBL.ValidateRequestApiKey()) { DekiContext.Current.Instance.Log.InfoFormat("user '{0}' authenticating being bypassed via apikey impersonation", userName); bypassAuthentication = true; } user = ExternalServiceSA.BuildUserFromAuthService(authService, user, userName, bypassAuthentication, externalName, password, out externalGroups); } // User was not found or did not authenticate with external provider if (user == null) { LoginAccessDenied(context, request, userName, null, password); } else { //New user creation from external provider if (user.ID == 0) { if (!autoCreateExternalUser) { LoginAccessDenied(context, request, userName, null, password); } } else { //user exists // TODO (steveb): ??? } if (user.UserActive) { user = UserBL.CreateOrUpdateUser(user); if (externalGroups != null) { UserBL.UpdateUsersGroups(user, externalGroups.ToArray()); } } } } else if (userFromToken != null) { // valid token exists that resolved to a user user = userFromToken; } else if (allowAnon) { // Anonymous user user = DbUtils.CurrentSession.Users_GetByName(DekiWikiService.ANON_USERNAME); } if (user == null) { //No credentials. Or token not provided or is invalid. LoginAccessDenied(context, request, null, null, password); } else if (!user.UserActive && !PermissionsBL.ValidateRequestApiKey()) { //If a valid api key is provided, override the disabled account flag throw new AuthUserDisabledForbiddenException(user.Name); } return(user); }
public static XDoc GetUserXmlVerbose(UserBE user, string relationAttr, bool showPrivateInfo, bool showGroups, bool showProperties) { XDoc userXml = GetUserXml(user, relationAttr, showPrivateInfo); userXml.Elem("date.created", user.CreateTimestamp); if (!IsAnonymous(user)) { PageBE homePage = GetHomePage(user); if (homePage != null && homePage.ID != 0) { userXml.Add(PageBL.GetPageXml(homePage, "home")); } } userXml.Start("status").Value(user.UserActive ? "active" : "inactive").End(); userXml.Start("date.lastlogin").Value(user.Touched).End(); userXml.Start("language").Value(user.Language).End(); userXml.Start("timezone").Value(user.Timezone).End(); ServiceBE authService = ServiceBL.GetServiceById(user.ServiceId); if (authService != null) { userXml.Add(ServiceBL.GetServiceXml(authService, "authentication")); } //Permissions for the user from user role userXml.Add(PermissionsBL.GetRoleXml(PermissionsBL.GetRoleById(user.RoleId), "user")); ulong effectivePermissions = PermissionsBL.CalculateEffectiveUserRights(user); //Effective permissions for the user from the role + group roles. userXml.Add(PermissionsBL.GetPermissionXml(effectivePermissions, "effective")); // Set of permissions revoked from the user userXml.Add(PermissionsBL.GetPermissionsRevokedXml(user)); // check if groups should be included if (showGroups) { userXml.Start("groups"); IList <GroupBE> groups = DbUtils.CurrentSession.Groups_GetByUser(user.ID); if (null != groups) { foreach (GroupBE g in groups) { userXml.Add(GroupBL.GetGroupXmlVerbose(g, null)); } } userXml.End(); } // retrieve properties for current user while providing an href for other users. if (showProperties && (DekiContext.Current != null && DekiContext.Current.User != null && DekiContext.Current.User.ID == user.ID)) { IList <ResourceBE> props = PropertyBL.Instance.GetUserProperties(user.ID); userXml = PropertyBL.Instance.GetPropertyXml(props, GetUri(user), null, null, userXml); } else { userXml.Start("properties").Attr("href", GetUri(user).At("properties")).End(); } // TODO Max: get <subscriptions> (watchlist) not implemented return(userXml); }
private static void ParseUserXml(XDoc userDoc, out uint?id, out string username, out string email, out string fullname, out ServiceBE authService, out RoleBE role, out bool?active, out string language, out string timezone) { username = userDoc["username"].AsText; email = userDoc["email"].AsText; fullname = userDoc["fullname"].AsText; language = userDoc["language"].AsText; timezone = userDoc["timezone"].AsText; string authserviceidstr = userDoc["service.authentication/@id"].AsText; string rolestr = userDoc["permissions.user/role"].AsText; string statusStr = userDoc["status"].AsText; authService = null; role = null; id = null; if (!userDoc["@id"].IsEmpty) { uint id_temp; if (!uint.TryParse(userDoc["@id"].Contents, out id_temp)) { throw new UserIdAttrInvalidArgumentException(); } id = id_temp; } if (!string.IsNullOrEmpty(authserviceidstr)) { uint serviceid; if (!uint.TryParse(authserviceidstr, out serviceid)) { throw new ServiceAuthIdAttrInvalidArgumentException(); } authService = ServiceBL.GetServiceById(serviceid); if (authService == null) { throw new ServiceDoesNotExistInvalidArgumentException(serviceid); } } if (!string.IsNullOrEmpty(rolestr)) { role = PermissionsBL.GetRoleByName(rolestr); if (role == null) { throw new RoleDoesNotExistInvalidArgumentException(rolestr); } } if (!string.IsNullOrEmpty(statusStr)) { switch (statusStr.ToLowerInvariant()) { case "active": active = true; break; case "inactive": active = false; break; default: throw new UserStatusAttrInvalidArgumentException(); } } else { active = null; } if (!string.IsNullOrEmpty(timezone)) { if (!timeZoneRegex.Match(timezone).Success) { throw new UserTimezoneInvalidArgumentException(); } } if (!string.IsNullOrEmpty(language)) { string[] validLanguages = DekiContext.Current.Instance.Languages.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); string tempLanguage = language; if (!Array.Exists(validLanguages, delegate(string temp) { return(temp.EqualsInvariantIgnoreCase(tempLanguage)); })) { throw new UserInvalidLanguageException(); } } }