示例#1
0
        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));
        }
示例#2
0
        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);
        }
示例#3
0
        /// <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);
        }
示例#4
0
        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);
        }
示例#5
0
        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);
        }
示例#6
0
        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);
        }
示例#8
0
 //--- 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));
 }
示例#10
0
        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);
        }
示例#11
0
 public IEnumerable <UserBE> GetAllUsers()
 {
     return(UserBL.GetAllUsers());
 }
示例#12
0
 public UserBE GetUserById(uint userId)
 {
     return(UserBL.GetUserById(userId));
 }
示例#13
0
 public XUri GetUri(UserBE user)
 {
     return(UserBL.GetUri(user));
 }
示例#14
0
 public bool IsAnonymous(UserBE user)
 {
     return(UserBL.IsAnonymous(user));
 }
示例#15
0
        //--- 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);
        }
示例#16
0
        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);
        }
示例#17
0
        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);
        }