public static XDoc GetArchivePageXml(uint pageid) { XDoc ret = XDoc.Empty; ArchiveBE page = DbUtils.CurrentSession.Archive_GetPageHeadById(pageid); if (page == null) { throw new PageArchiveLogicNotFoundException(pageid); } //Retrieve metadata about the deletion to populate page info TransactionBE t = DbUtils.CurrentSession.Transactions_GetById(page.TransactionId); DateTime deleteTs = DateTime.MinValue; UserBE deletedBy = null; if (t != null) { deletedBy = UserBL.GetUserById(t.UserId); deleteTs = t.TimeStamp; } return(GetArchivePageXml(ret, page, deletedBy, deleteTs)); }
private static UserBE ValidateAuthToken(string authToken, bool impersonationOnly) { var context = DekiContext.Current; var token = ParseToken(authToken); var instance = context.Instance; if (token == null) { return(null); } UserBE user; if (token.IsImpersonationToken) { if (ValidateImpersonationToken(context, token)) { user = string.IsNullOrEmpty(token.Username) ? UserBL.GetUserById(token.UserId) : UserBL.GetUserByName(token.Username); instance.Log.InfoFormat("APIKEY impersonation token provided. Impersonating user '{0}' ({1})", user.Name, user.ID); return(user); } return(null); } // only allowing impersonation tokens? if (impersonationOnly) { return(null); } // check timestamp if (token.Timestamp < DateTime.UtcNow.Subtract(instance.AuthCookieExpirationTime) && instance.AuthCookieExpirationTime.TotalSeconds > 0) { return(null); } // retrieve associated user object user = UserBL.GetUserById(token.UserId); if (user == null) { return(null); } // TODO Max: Consider logging this as an intrusion attempt. return(authToken == CreateAuthTokenForUser(user, token.Timestamp) ? user : null); }
/// <summary> /// Get a user out of an authtoken from a request if it's valid. /// </summary> /// <returns></returns> private static UserBE UserFromAuthTokenInRequest(DreamContext context, bool impersonationOnly) { DreamMessage request = context.Request; string authToken = context.Uri.GetParam(DekiWikiService.AUTHTOKEN_URIPARAM, null); UserBE user = null; // Check if auth token is in a cookie if ((authToken == null) && request.HasCookies) { DreamCookie authCookie = DreamCookie.GetCookie(request.Cookies, DekiWikiService.AUTHTOKEN_COOKIENAME); if ((authCookie != null) && (!authCookie.Expired)) { authToken = authCookie.Value; } } // Check if auth token is in a header or passed in as query parameter authToken = authToken ?? request.Headers[DekiWikiService.AUTHTOKEN_HEADERNAME]; // Extract user name from auth token if it's valid if (authToken != null) { user = ValidateAuthToken(authToken, impersonationOnly); // check whether licensestate prevents user from being authenticated var license = DekiContext.Current.LicenseManager; LicenseStateType licensestate = license.LicenseState; if ((licensestate == LicenseStateType.EXPIRED || licensestate == LicenseStateType.INVALID || licensestate == LicenseStateType.INACTIVE) && !PermissionsBL.IsUserAllowed(user, Permissions.ADMIN) ) { if (DekiContext.Current.Instance.Log.IsWarnEnabled) { switch (licensestate) { case LicenseStateType.EXPIRED: DekiContext.Current.Instance.Log.WarnFormat("UserFromAuthTokenInRequest: Expired license {0}, reverting non-admin user to anonymous", license.LicenseExpiration); break; case LicenseStateType.INVALID: DekiContext.Current.Instance.Log.WarnFormat("UserFromAuthTokenInRequest: Invalid license, reverting non-admin user to anonymous"); break; case LicenseStateType.INACTIVE: DekiContext.Current.Instance.Log.WarnFormat("UserFromAuthTokenInRequest: Inactive license, reverting non-admin user to anonymous"); break; } } user = null; } else { DekiContext.Current.AuthToken = authToken; } } if (PermissionsBL.ValidateRequestApiKey()) { uint userIdOverride = 0; if (uint.TryParse(context.GetParam(DekiWikiService.IMPERSONATE_USER_QUERYNAME, null), out userIdOverride)) { UserBE userOverride = UserBL.GetUserById(userIdOverride); if (userOverride != null) { user = userOverride; DekiContext.Current.Instance.Log.InfoFormat("APIKEY provided. Impersonating user id '{0}': {1}", user.ID, user.Name); } } } return(user); }
private XDoc AppendFileXml(XDoc doc, ResourceBE file, string fileSuffix, bool?explicitRevisionInfo, UserBE updatedByUser, PageBE parentPage) { bool requiresEnd = false; string fileElement = string.IsNullOrEmpty(fileSuffix) ? "file" : "file." + fileSuffix; if (doc == null || doc.IsEmpty) { doc = new XDoc(fileElement); } else { doc.Start(fileElement); requiresEnd = true; } doc.Attr("id", file.MetaXml.FileId ?? 0); doc.Attr("revision", file.Revision); doc.Attr("res-id", file.ResourceId); if (file.IsHidden) { doc.Attr("hidden", true); } doc.Attr("href", GetUriInfo(file, explicitRevisionInfo)); doc.Start("filename").Value(file.Name).End(); //Description comes from a property string description = string.Empty; if (!ArrayUtil.IsNullOrEmpty(file.ChildResources)) { ResourceBE descProp = Array.Find(file.ChildResources, p => p != null && p.ResourceType == ResourceBE.Type.PROPERTY && p.Name.EqualsInvariantIgnoreCase(PropertyBL.PROP_DESC)); if (descProp != null) { description = descProp.Content.ToText(); } } doc.Start("description").Value(description).End(); doc.Start("contents") .Attr("type", file.MimeType == null ? null : file.MimeType.ToString()) .Attr("size", file.Size); if ((file.MetaXml.ImageHeight ?? 0) > 0 && (file.MetaXml.ImageWidth ?? 0) > 0) { doc.Attr("width", file.MetaXml.ImageWidth.Value); doc.Attr("height", file.MetaXml.ImageHeight.Value); } doc.Attr("href", GetUriContent(file, explicitRevisionInfo)); doc.End(); //contents if ((file.MetaXml.ImageWidth ?? 0) > 0 && (file.MetaXml.ImageHeight ?? 0) > 0) { string previewMime = AttachmentPreviewBL.ResolvePreviewMime(file.MimeType).ToString(); doc.Start("contents.preview") .Attr("rel", "thumb") .Attr("type", previewMime) .Attr("maxwidth", _dekiContext.Instance.ImageThumbPixels) .Attr("maxheight", _dekiContext.Instance.ImageThumbPixels) .Attr("href", GetUriContent(file, explicitRevisionInfo).With("size", "thumb")); if (!file.IsHeadRevision() || (explicitRevisionInfo ?? false)) { doc.Attr("revision", file.Revision); } doc.End(); //contents.preview: thumb doc.Start("contents.preview") .Attr("rel", "webview") .Attr("type", previewMime) .Attr("maxwidth", _dekiContext.Instance.ImageWebviewPixels) .Attr("maxheight", _dekiContext.Instance.ImageWebviewPixels) .Attr("href", GetUriContent(file, explicitRevisionInfo).With("size", "webview")); if (!file.IsHeadRevision() || (explicitRevisionInfo ?? false)) { doc.Attr("revision", file.Revision); } doc.End(); //contents.preview: webview } doc.Start("date.created").Value(file.Timestamp).End(); if (updatedByUser != null) { doc.Add(UserBL.GetUserXml(updatedByUser, "createdby", Utils.ShowPrivateUserInfo(updatedByUser))); } if (file.ResourceIsDeleted && ((file.ChangeMask & ResourceBE.ChangeOperations.DELETEFLAG) == ResourceBE.ChangeOperations.DELETEFLAG)) { if (updatedByUser != null) { doc.Add(UserBL.GetUserXml(updatedByUser, "deletedby", Utils.ShowPrivateUserInfo(updatedByUser))); } doc.Start("date.deleted").Value(file.Timestamp).End(); } if (file.IsHeadRevision() && !(explicitRevisionInfo ?? false) && !file.ResourceIsDeleted) { uint filteredCount = _session.Resources_GetRevisionCount(file.ResourceId, DEFAULT_REVISION_FILTER); doc.Start("revisions"); doc.Attr("count", filteredCount); doc.Attr("totalcount", file.Revision); doc.Attr("href", GetUri(file).At("revisions")); doc.End(); } else { if (file.ChangeMask != ResourceBE.ChangeOperations.UNDEFINED) { doc.Start("user-action").Attr("type", file.ChangeMask.ToString().ToLowerInvariant()).End(); } } //parent page is passed in for verbose output only if (parentPage != null) { doc.Add(PageBL.GetPageXml(parentPage, "parent")); } if (file.ChildResources != null) { List <ResourceBE> properties = new List <ResourceBE>(); foreach (ResourceBE p in file.ChildResources) { properties.Add(p); } doc = PropertyBL.Instance.GetPropertyXml(properties.ToArray(), GetUri(file), null, null, doc); } if (file.IsHidden) { uint?userIdHiddenBy = file.MetaXml.RevisionHiddenUserId; if (userIdHiddenBy != null) { UserBE userHiddenBy = UserBL.GetUserById(userIdHiddenBy.Value); if (userHiddenBy != null) { doc.Add(UserBL.GetUserXml(userHiddenBy, "hiddenby", Utils.ShowPrivateUserInfo(userHiddenBy))); } } doc.Elem("date.hidden", file.MetaXml.RevisionHiddenTimestamp ?? DateTime.MinValue); doc.Elem("description.hidden", file.MetaXml.RevisionHiddenComment ?? string.Empty); } if (requiresEnd) { doc.End(); //file } return(doc); }
public static void InitializeCustomDekiScriptHeaders(PageBE page) { var current = DreamContext.Current; DekiScriptMap env = current.GetState <DekiScriptMap>("pageimplicitenv-" + page.ID); // check if we already have an initialized environment if (env == null) { DekiContext deki = DekiContext.Current; DekiInstance instance = deki.Instance; env = new DekiScriptMap(); // add site fields DekiScriptMap siteFields = new DekiScriptMap(); siteFields.Add("name", DekiScriptExpression.Constant(instance.SiteName)); siteFields.Add("host", DekiScriptExpression.Constant(deki.UiUri.Uri.Host)); siteFields.Add("language", DekiScriptExpression.Constant(instance.SiteLanguage)); siteFields.Add("uri", DekiScriptExpression.Constant(deki.UiUri.Uri.ToString())); siteFields.Add("id", DekiScriptExpression.Constant(instance.Id)); env.Add("site", siteFields); // add page fields DekiScriptMap pageFields = new DekiScriptMap(); pageFields.Add("title", DekiScriptExpression.Constant(page.Title.AsUserFriendlyName())); pageFields.Add("path", DekiScriptExpression.Constant(page.Title.AsPrefixedDbPath())); pageFields.Add("namespace", DekiScriptExpression.Constant(Title.NSToString(page.Title.Namespace))); pageFields.Add("id", DekiScriptExpression.Constant(page.ID.ToString())); pageFields.Add("uri", DekiScriptExpression.Constant(Utils.AsPublicUiUri(page.Title))); pageFields.Add("date", DekiScriptExpression.Constant(page.TimeStamp.ToString("R"))); pageFields.Add("language", DekiScriptExpression.Constant(string.IsNullOrEmpty(page.Language) ? null : page.Language)); env.Add("page", pageFields); // add user fields DekiScriptMap userFields = new DekiScriptMap(); if (deki.User != null) { UserBE user = deki.User; userFields.Add("id", DekiScriptExpression.Constant(user.ID.ToString())); userFields.Add("name", DekiScriptExpression.Constant(user.Name)); userFields.Add("uri", DekiScriptExpression.Constant(Utils.AsPublicUiUri(Title.FromDbPath(NS.USER, user.Name, null)))); userFields.Add("emailhash", DekiScriptExpression.Constant(StringUtil.ComputeHashString((user.Email ?? string.Empty).Trim().ToLowerInvariant(), Encoding.UTF8))); userFields.Add("anonymous", DekiScriptExpression.Constant(UserBL.IsAnonymous(user).ToString().ToLowerInvariant())); userFields.Add("language", DekiScriptExpression.Constant(string.IsNullOrEmpty(user.Language) ? null : user.Language)); } else { userFields.Add("id", DekiScriptExpression.Constant("0")); userFields.Add("name", DekiScriptExpression.Constant(string.Empty)); userFields.Add("uri", DekiScriptExpression.Constant(string.Empty)); userFields.Add("emailhash", DekiScriptExpression.Constant(string.Empty)); userFields.Add("anonymous", DekiScriptExpression.Constant("true")); userFields.Add("language", DekiScriptNil.Value); } env.Add("user", userFields); // store env for later current.SetState("pageimplicitenv-" + page.ID, env); } // set implicit environment DreamContext.Current.SetState(env); }
private static XDoc AppendCommentXml(XDoc doc, CommentBE comment, string suffix, bool?includeParentInfo) { bool requiresEnd = false; string commentElement = string.IsNullOrEmpty(suffix) ? "comment" : "comment." + suffix; if (doc == null || doc.IsEmpty) { doc = new XDoc(commentElement); } else { doc.Start(commentElement); requiresEnd = true; } doc.Attr("id", comment.Id).Attr("href", CommentBL.GetUri(comment)); //include parentinfo by default if the parent page is populated PageBE page = PageBL.GetPageById(comment.PageId); if (page != null && (includeParentInfo ?? true)) { doc.Add(PageBL.GetPageXml(page, "parent")); } UserBE posterUser = UserBL.GetUserById(comment.PosterUserId); if (posterUser != null) { doc.Add(UserBL.GetUserXml(posterUser, "createdby", Utils.ShowPrivateUserInfo(posterUser))); } doc.Start("date.posted").Value(comment.CreateDate).End(); doc.Start("title").Value(comment.Title).End(); doc.Start("number").Value(comment.Number).End(); //Note (MaxM): Replytoid/replies not yet exposed //if (ReplyToId.HasValue) { // doc.Start("comment.replyto") // .Attr("number", ReplyToId.Value.ToString()) // .Attr("href", DekiContext.Current.ApiUri.At("pages", PageId.ToString(), "comments", ReplyToId.Value.ToString())).End(); //} bool displayContent = true; //Only display content for nondeleted comments or for admins if (comment.IsCommentMarkedAsDeleted) { displayContent = PermissionsBL.IsUserAllowed(DekiContext.Current.User, Permissions.ADMIN); } if (displayContent) { doc.Start("content") .Attr("type", comment.ContentMimeType) .Attr("href", CommentBL.GetUri(comment).At("content")) .Value(comment.Content).End(); } if (comment.LastEditUserId.HasValue) { UserBE lastEditUser = UserBL.GetUserById(comment.LastEditUserId.Value); if (null != lastEditUser) { doc.Add(UserBL.GetUserXml(lastEditUser, "editedby", Utils.ShowPrivateUserInfo(lastEditUser))); doc.Start("date.edited").Value(comment.LastEditDate).End(); } } if (comment.IsCommentMarkedAsDeleted && comment.DeleterUserId.HasValue) { UserBE deleteUser = UserBL.GetUserById(comment.DeleterUserId.Value); if (null != deleteUser) { doc.Add(UserBL.GetUserXml(deleteUser, "deletedby", Utils.ShowPrivateUserInfo(deleteUser))); doc.Start("date.deleted").Value(comment.DeleteDate).End(); } } if (requiresEnd) { doc.End(); //comment } return(doc); }
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); }
//--- Methods --- public void UpdateUser(UserBE user) { UserBL.UpdateUser(user); }
//--- Class Methods --- public static bool IsSafeMode(PageBE page) { return(!PermissionsBL.IsUserAllowed(UserBL.GetUserById(page.UserID), page, Permissions.UNSAFECONTENT)); }
private XDoc AppendPropertyXml(XDoc doc, ResourceBE property, XUri parentResourceUri, string propSuffix, bool?explicitRevisionInfo, uint?contentCutoff, Dictionary <uint, UserBE> usersById) { bool requiresEnd = false; explicitRevisionInfo = explicitRevisionInfo ?? false; string propElement = string.IsNullOrEmpty(propSuffix) ? "property" : "property." + propSuffix; if (doc == null || doc.IsEmpty) { doc = new XDoc(propElement); } else { doc.Start(propElement); requiresEnd = true; } //Build the base uri to the property bool includeContents = property.Size <= (contentCutoff ?? DEFAULT_CONTENT_CUTOFF) && (property.MimeType.Match(MimeType.ANY_TEXT) ); //TODO: contents null check doc.Attr("name", property.Name) .Attr("href", /*explicitRevisionInfo.Value ? property.PropertyInfoUri(parentResourceUri, true) : */ property.PropertyInfoUri(parentResourceUri)); if (property.IsHeadRevision()) { doc.Attr("etag", property.ETag()); } /* PROPERTY REVISIONS: if(!property.IsHeadRevision() || explicitRevisionInfo.Value) { * revisions not currently exposed. * doc.Attr("revision", property.Revision); * } */ /* PROPERTY REVISIONS: doc.Start("revisions") * .Attr("count", property.ResourceHeadRevision) * .Attr("href", property.UriRevisions()) * .End(); */ string content = null; if (includeContents) { content = property.Content.ToText(); } doc.Start("contents") .Attr("type", property.MimeType.ToString()) .Attr("size", property.Size) .Attr("href", /*PROPERTY REVISIONS: explicitRevisionInfo.Value ? property.PropertyContentUri(true) : */ property.PropertyContentUri(parentResourceUri)) .Value(content) .End(); doc.Elem("date.modified", property.Timestamp); UserBE userModified; usersById.TryGetValue(property.UserId, out userModified); if (userModified != null) { doc.Add(UserBL.GetUserXml(userModified, "modified", Utils.ShowPrivateUserInfo(userModified))); } doc.Elem("change-description", property.ChangeDescription); if (property.Deleted) { UserBE userDeleted; usersById.TryGetValue(property.UserId, out userDeleted); if (userDeleted != null) { doc.Add(UserBL.GetUserXml(userDeleted, "deleted", Utils.ShowPrivateUserInfo(userDeleted))); } doc.Elem("date.deleted", property.Timestamp); } if (requiresEnd) { doc.End(); //property } return(doc); }
public IEnumerable <UserBE> GetAllUsers() { return(UserBL.GetAllUsers()); }
public UserBE GetUserById(uint userId) { return(UserBL.GetUserById(userId)); }
public XUri GetUri(UserBE user) { return(UserBL.GetUri(user)); }
public bool IsAnonymous(UserBE user) { return(UserBL.IsAnonymous(user)); }
//--- 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 GetInstanceSettingsAsDoc(SiteSettingsRetrievalSettings retrieve) { var instance = DekiContext.Current.Instance; string cachekey = retrieve.IncludeHidden ? CACHE_SETTINGSDOC_WITHHIDDEN : CACHE_SETTINGSDOC; XDoc result = instance.Cache.Get <XDoc>(cachekey, null); if (result == null) { Dictionary <string, ConfigValue> config = GetInstanceSettings(); List <KeyValuePair <string, string> > items = new List <KeyValuePair <string, string> >(); lock (config) { foreach (KeyValuePair <string, ConfigValue> entry in config) { if (entry.Value.IsHidden && !retrieve.IncludeHidden) { continue; } // check if overwritten setting was an element int index = entry.Key.LastIndexOf('/'); bool isElement = ((index + 1) < entry.Key.Length) && (entry.Key[index + 1] != '@'); items.Add(new KeyValuePair <string, string>(entry.Key, entry.Value.Value)); if (isElement) { if (entry.Value.IsReadOnly) { // we need to add a 'readonly' attribute items.Add(new KeyValuePair <string, string>(entry.Key + READONLY_SUFFIX, "true")); } if (entry.Value.IsHidden) { // we need to add a 'hidden' attribute items.Add(new KeyValuePair <string, string>(entry.Key + HIDDEN_SUFFIX, "true")); } } } } //Ensure that attributes are after their associated elements to ensure that the #text and the @attribute are part of the same element rather than creating a new element with just the #text //after the attribute. Consider moving this to Dream XDocFactory.From items.Sort((left, right) => StringUtil.CompareInvariant(left.Key, right.Key)); result = XDocFactory.From(items, "config"); var u = DbUtils.CurrentSession.Users_GetByName(UserBL.ANON_USERNAME); var anonDoc = UserBL.GetUserXmlVerbose(u, null, Utils.ShowPrivateUserInfo(u), true, true); result.InsertValueAt(ANONYMOUS_USER, anonDoc.ToJson()); // Add license information var licenseManager = DekiContext.Current.LicenseManager; var licenseDoc = licenseManager.GetLicenseDocument(false).Clone(); licenseDoc.Elem("type", licenseDoc["@type"].Contents); _log.Debug("Added private information."); licenseDoc["support-agreement"].Remove(); licenseDoc["source-license"].Remove(); licenseDoc["license.public"].Remove(); licenseDoc["grants/service-license"].RemoveAll(); var now = DateTime.UtcNow; foreach (var capability in licenseDoc["grants/*[@date.expire]"]) { if (capability["@date.expire"].AsDate < now) { capability.Remove(); } } XDoc originalLicenseElems = result["license"]; XDoc clonedOriginalLicenseElems = XDoc.Empty; if (!originalLicenseElems.IsEmpty) { clonedOriginalLicenseElems = originalLicenseElems.Clone(); originalLicenseElems.Remove(); licenseDoc.AddNodes(clonedOriginalLicenseElems); } result.Start(LICENSE).AddNodes(licenseDoc).End(); AddVersionInfo(result); instance.Cache.Set(cachekey, result.Clone(), DateTime.UtcNow.AddSeconds(60)); } else { // TODO: remove the clone once cached settings come out of IKeyValueCache (i.e. are serialized) // NOTE(cesarn): We need to clone it because we are stripping and adding // elements depending on permissions and what is requested, but we do not // want to change the cached version that contains everything. result = result.Clone(); } if (!retrieve.IncludeAnonymousUser) { result[ANONYMOUS_USER].Remove(); _log.Debug("Removing anonymous's user information."); } if (!retrieve.IncludeLicense) { var mandatoryLicenseInfo = new XDoc(LICENSE).Start("state").Attr("readonly", "true").Value(result[LICENSE_STATE].Contents).End(); if (DekiContext.Current.LicenseManager.LicenseExpiration != DateTime.MaxValue) { mandatoryLicenseInfo.Start("expiration").Attr("readonly", "true").Value(result[LICENSE_EXPIRATION].Contents).End(); } var productKey = LicenseBL.Instance.BuildProductKey(); if (!String.IsNullOrEmpty(productKey)) { mandatoryLicenseInfo.Start("productkey").Attr("readonly", "true").Value(result[LICENSE_PRODUCTKEY].Contents).End(); } result[LICENSE].Remove(); _log.Debug("Removing private information elements"); result.Start(LICENSE).AddNodes(mandatoryLicenseInfo).End(); } result.InsertValueAt("api/@href", DekiContext.Current.Deki.Self.Uri.AsPublicUri().ToString()); return(result); }
private static UserBE UpdateUserFromXml(UserBE userToUpdate, XDoc userDoc, string username, string email, string fullname, ServiceBE authservice, RoleBE role, bool?active, string externalusername, string externalpassword, string language, string timezone, out List <GroupBE> externalGroups) { externalGroups = null; if (userToUpdate.Name != username && !string.IsNullOrEmpty(username)) { if (UserBL.IsAnonymous(userToUpdate)) { throw new UserAnonymousEditInvalidOperationException(); } userToUpdate = RenameUser(userToUpdate, username, fullname ?? userToUpdate.RealName); } //Modify a user's authentication service if (authservice != null && authservice.Id != userToUpdate.ServiceId) { if (UserBL.IsAnonymous(userToUpdate)) { throw new UserAnonymousEditInvalidOperationException(); } if (ServiceBL.IsLocalAuthService(authservice)) { //external to local userToUpdate.ExternalName = null; userToUpdate.ServiceId = authservice.Id; } else { //(local or external) to external userToUpdate = ExternalServiceSA.BuildUserFromAuthService(authservice, userToUpdate, userToUpdate.Name, true, externalusername, externalpassword, out externalGroups); if (userToUpdate == null) { throw new UserAuthChangeFatalException(); } //Does the external account already exist? UserBE matchingExternalAccount = DbUtils.CurrentSession.Users_GetByExternalName(userToUpdate.ExternalName, userToUpdate.ServiceId); if (matchingExternalAccount != null) { throw new ExternalUserExistsConflictException(matchingExternalAccount.Name, matchingExternalAccount.ExternalName, matchingExternalAccount.ServiceId); } } } if (email != null) { if (UserBL.IsAnonymous(userToUpdate) && email != userToUpdate.Email) { throw new UserAnonymousEditInvalidOperationException(); } userToUpdate.Email = email; } if (!string.IsNullOrEmpty(fullname)) { userToUpdate.RealName = fullname; } if (active != null) { // disabling user if (userToUpdate.UserActive && !active.Value) { // cannot disable anonymous user if (UserBL.IsAnonymous(userToUpdate)) { throw new UserAnonymousDeactivationInvalidOperationException(); } // cannot disable owner if (DekiContext.Current.LicenseManager.GetSiteOwnerUserId().GetValueOrDefault(0) == userToUpdate.ID) { throw new UserOwnerDeactivationConflict(); } } //throw exception if licensing does not allow activating a user if (!userToUpdate.UserActive && active.Value) { DekiContext.Current.LicenseManager.IsUserCreationAllowed(true); } userToUpdate.UserActive = active.Value; } if (role != null && role.ID != userToUpdate.RoleId) { PermissionsBL.CheckUserAllowed(DekiContext.Current.User, Permissions.ADMIN); userToUpdate.RoleId = role.ID; } if (language != null) { userToUpdate.Language = language; } if (timezone != null) { userToUpdate.Timezone = timezone; } return(userToUpdate); }