Esempio n. 1
0
        /*
         * Changes the password for currently logged in user
         */
        public static void ChangePassword(ApplicationContext context, Node args)
        {
            // Retrieving new password, and doing some basic sanity check.
            string password = args.GetExValue(context, "");

            if (string.IsNullOrEmpty(password))
            {
                throw new LambdaException("No password supplied", args, context);
            }

            string username = context.Ticket.Username;

            // Retrieving system salt before we enter write lock.
            var serverSalt = context.RaiseEvent(".p5.auth.get-server-salt").Get <string> (context);

            // Locking access to password file as we edit user object
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Changing user's password
                // Then salting password with user salt and system, before salting it with system salt
                var userPasswordFingerprint = context.RaiseEvent("p5.crypto.hash.create-sha256", new Node("", serverSalt + password)).Get <string> (context);
                authFile ["users"] [username] ["password"].Value = userPasswordFingerprint;
            });
        }
Esempio n. 2
0
        /*
         * Changes the password for currently logged in user.
         */
        public static void ChangeMyPassword(ApplicationContext context, Node args)
        {
            // Retrieving new password.
            var password = args.GetExValue(context, "");

            // Verifying new password is good.
            if (!IsGoodPassword(context, password))
            {
                // New password was not accepted, throwing an exception.
                args.FindOrInsert("password").Value = "xxx";
                throw new LambdaSecurityException(
                          "Password didn't obey by your configuration settings, which are as follows; " +
                          PasswordRuleDescription(context),
                          args,
                          context);
            }

            // Figuring out username of current context.
            var username = context.Ticket.Username;

            // Salting and hashing password before we enter "auth" file lock to minimize the amount of time file is locked.
            password = SaltAndHashPassword(context, password);

            // Locking access to password file as we edit user object.
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Changing user's password by first salting it, and then hashing it.
                authFile ["users"] [username] ["password"].Value = password;
            });
        }
Esempio n. 3
0
        /*
         * Changes password of "root" account, but only if existing root account's password
         * is null. Used during setup of system
         */
        public static void SetRootPassword(ApplicationContext context, Node args)
        {
            // Retrieving password given.
            var password = args.GetExChildValue <string> ("password", context);

            // Verifying password is accepted.
            if (!Passwords.IsGoodPassword(context, password))
            {
                // Password was not accepted, throwing an exception.
                args.FindOrInsert("password").Value = "xxx";
                throw new LambdaSecurityException(
                          "Password didn't obey by your configuration settings, which are as follows; " +
                          Passwords.PasswordRuleDescription(context),
                          args,
                          context);
            }

            // Creating root account.
            var rootAccountNode = new Node("", "root");

            rootAccountNode.Add("password", password);
            rootAccountNode.Add("role", "root");
            Users.CreateUser(context, rootAccountNode);

            // Creating "guest account" section, which is needed for settings among other things.
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                authFile ["users"].Add(context.RaiseEvent(".p5.auth.get-default-context-username").Get <string> (context)).LastChild
                .Add("role", context.RaiseEvent(".p5.auth.get-default-context-role").Get <string> (context));
            });
        }
        /*
         * Retrieves a specific user from system
         */
        public static void DeleteUser(ApplicationContext context, Node args)
        {
            // Locking access to password file as we create new user object
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Iterating all users requested deleted by caller
                foreach (var idxUsername in XUtil.Iterate <string> (context, args))
                {
                    // Checking if user exist
                    if (authFile ["users"] [idxUsername] == null)
                    {
                        throw new LambdaException(
                            string.Format("User '{0}' does not exist", idxUsername),
                            args,
                            context);
                    }

                    // Deleting currently iterated user
                    authFile["users"][idxUsername].UnTie();

                    // Deleting user's home directory
                    context.Raise("p5.io.folder.delete", new Node("", "/users/" + idxUsername + "/"));
                }
            });
        }
Esempio n. 5
0
        /*
         * Edits an existing user
         */
        public static void EditUser(ApplicationContext context, Node args)
        {
            // Retrieving username, and sanity checking invocation.
            string username = args.GetExValue <string> (context);

            if (args ["username"] != null)
            {
                throw new LambdaSecurityException("Cannot change username for user", args, context);
            }

            // Retrieving new password and role, defaulting to null, which will not update existing values.
            string newPassword = args.GetExChildValue <string> ("password", context);
            string newRole     = args.GetExChildValue <string> ("role", context);

            // Retrieving system salt before we enter write lock. (important, since otherwise we'd have a deadlock condition here).
            var serverSalt = newPassword == null ? null : context.RaiseEvent(".p5.auth.get-server-salt").Get <string> (context);

            // Locking access to password file as we edit user object.
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Checking to see if user exist.
                if (authFile ["users"] [username] == null)
                {
                    throw new LambdaException(
                        "Sorry, that user does not exist",
                        args,
                        context);
                }

                // Updating user's password, but only if a new password was supplied by caller.
                if (!string.IsNullOrEmpty(newPassword))
                {
                    // Making sure we salt password with system salt, before we create our SHA256 value, which is what we actually store in our "auth" file.
                    var userPasswordFingerprint = context.RaiseEvent("p5.crypto.hash.create-sha256", new Node("", serverSalt + newPassword)).Get <string> (context);
                    authFile ["users"] [username] ["password"].Value = userPasswordFingerprint;
                }

                // Updating user's role, if a new role was supplied by caller.
                if (newRole != null)
                {
                    authFile ["users"] [username] ["role"].Value = newRole;
                }

                // Checking if caller wants to edit settings.
                if (args.Name == "p5.auth.users.edit")
                {
                    // Removing old settings.
                    authFile ["users"] [username].RemoveAll(ix => ix.Name != "password" && ix.Name != "role");

                    // Adding all other specified objects to user.
                    foreach (var idxNode in args.Children.Where(ix => ix.Name != "password" && ix.Name != "role"))
                    {
                        authFile ["users"] [username].Add(idxNode.Clone());
                    }
                }
            });
        }
Esempio n. 6
0
 /*
  * Sets the GnuPG keypair for server.
  */
 public static void SetFingerprint(ApplicationContext context, Node args, string fingerprint)
 {
     AuthFile.ModifyAuthFile(context, delegate(Node node) {
         if (node [GnuPgpFingerprintNodeName] != null)
         {
             throw new LambdaSecurityException("Tried to change GnuPG keypair after initial creation", args, context);
         }
         node.Add(GnuPgpFingerprintNodeName, fingerprint);
     });
 }
 /*
  * Sets the server salt for application
  */
 public static void SetServerSalt(ApplicationContext context, Node args, string salt)
 {
     AuthFile.ModifyAuthFile(context, delegate(Node node) {
         if (node.Children.Find(delegate(Node ix) { return(ix.Name == "server-salt"); }) != null)
         {
             throw new LambdaSecurityException("Tried to change server salt after initial creation", args, context);
         }
         node.FindOrInsert("server-salt").Value = salt;
     });
 }
        /*
         * Edits an existing user
         */
        public static void EditUser(ApplicationContext context, Node args)
        {
            string username = args.GetExValue <string>(context);
            string password = args.GetExChildValue <string>("password", context);
            string userRole = args.GetExChildValue <string>("role", context);

            if (args["username"] != null)
            {
                throw new LambdaSecurityException("Cannot change username for user", args, context);
            }

            // Locking access to password file as we edit user object
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Checking to see if user exist
                if (authFile["users"][username] == null)
                {
                    throw new LambdaException(
                        "Sorry, that user does not exist",
                        args,
                        context);
                }

                // Updating user's password, if a new one was given
                if (!string.IsNullOrEmpty(password))
                {
                    // Changing user's password
                    // Creating user salt, and retrieving system salt
                    var serverSalt = context.Raise(".p5.auth.get-server-salt").Get <string> (context);

                    // Then salting password with user salt and system, before salting it with system salt
                    var userPasswordFingerprint = context.Raise("p5.crypto.hash.create-sha256", new Node("", serverSalt + password)).Get <string> (context);
                    authFile ["users"][username]["password"].Value = userPasswordFingerprint;
                }

                // Updating user's role
                if (userRole != null)
                {
                    authFile["users"][username]["role"].Value = userRole;
                }

                // Removing old settings
                authFile["users"][username].Children.RemoveAll(ix => ix.Name != "password" && ix.Name != "role");

                // Adding all other specified objects to user
                foreach (var idxNode in args.Children.Where(ix => ix.Name != "password" && ix.Name != "role"))
                {
                    authFile["users"][username].Add(idxNode.Clone());
                }
            });
        }
Esempio n. 9
0
 /*
  * Sets the server salt for server.
  */
 public static void SetServerSalt(ApplicationContext context, Node args, byte[] salt)
 {
     using (var sha512 = SHA512.Create()) {
         salt = sha512.ComputeHash(salt);
     }
     AuthFile.ModifyAuthFile(context, delegate(Node node) {
         if (node.Children.Any(ix => ix.Name == "server-salt"))
         {
             throw new LambdaSecurityException("Tried to change server salt after initial creation", args, context);
         }
         node.Add("server-salt", salt);
     });
 }
Esempio n. 10
0
        /*
         * Returns all access objects for system.
         */
        public static void SetAccess(ApplicationContext context, Node args)
        {
            // Locking access to password file as we create new access object.
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Verifying access rights exists.
                if (authFile ["access"] == null)
                {
                    authFile.Add("access");
                }

                // Retrieving access root node.
                var access = authFile ["access"];

                // Clearing all previous access objects.
                access.Clear();

                // Iterating all access objects supplied by caller, adding them to our access node.
                var newAccessRights = XUtil.Iterate <Node> (context, args).ToList();
                foreach (var idxAccess in newAccessRights)
                {
                    // Sanity checking.
                    var val = idxAccess.GetExValue(context, "");
                    if (string.IsNullOrEmpty(val))
                    {
                        // Creating a new random GUID as the ID of our access object.
                        val             = Guid.NewGuid().ToString();
                        idxAccess.Value = val;
                    }
                    else
                    {
                        // Verifying access ID is unique.
                        if (access.Children.Any(ix => ix.Get(context, "") == val))
                        {
                            throw new LambdaException("Each access right must have a unique name/value combination, and there's already another access right with the same name/value combination in your access list", idxAccess, context);
                        }
                    }

                    // Sanity checking access object.
                    if (idxAccess.Count == 0)
                    {
                        throw new LambdaException("There's no actual content in your access object", idxAccess, context);
                    }

                    // Adding currently iterated access object.
                    access.Add(idxAccess.Clone());
                }
            });
        }
        /*
         * Changes the settings for currently logged in user
         */
        public static void ChangeSettings(ApplicationContext context, Node args)
        {
            // Getting username for current context.
            string username = context.Ticket.Username;

            // Making sure default user cannot change his settings.
            if (context.Ticket.IsDefault)
            {
                throw new LambdaSecurityException("The default user cannot change his settings", args, context);
            }

            // Verifying that there's no "funny business" going on here.
            if (args ["password"] != null || args ["role"] != null)
            {
                throw new LambdaSecurityException("You cannot change your password or role with this Active Event", args, context);
            }

            // Locking access to password file as we edit user object
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Checking if invocation is for a single section, or if it's for everything.
                var section = args.GetExValue(context, "");
                if (string.IsNullOrEmpty(section))
                {
                    // Removing old settings
                    authFile ["users"] [username].RemoveAll(ix => ix.Name != "password" && ix.Name != "role");

                    // Changing all settings for user
                    foreach (var idxNode in args.Children)
                    {
                        authFile ["users"] [username].Add(idxNode.Clone());
                    }
                }
                else if (args.Count == 1)
                {
                    // Removing old settings
                    authFile ["users"] [username] [section]?.UnTie();

                    // Changing all settings for user.
                    authFile ["users"] [username].Add(args.FirstChild.Clone());
                }
                else
                {
                    // Oops, can't set a single section to multiple values.
                    throw new LambdaException("You can't set a single section to multiple values", args, context);
                }
            });
        }
Esempio n. 12
0
        /*
         * Changes the settings for currently logged in user
         */
        public static void ChangeSettings(ApplicationContext context, Node args)
        {
            string username = context.Ticket.Username;

            // Locking access to password file as we edit user object
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Removing old settings
                authFile["users"][username].Children.RemoveAll(ix => ix.Name != "password" && ix.Name != "role");

                // Changing all settings for user
                foreach (var idxNode in args.Children)
                {
                    authFile["users"][username].Add(idxNode.Clone());
                }
            });
        }
        /*
         * Changes the password for currently logged in user
         */
        public static void ChangePassword(ApplicationContext context, Node args)
        {
            // Retrieving new password, and doing some basic sanity check.
            string password = args.GetExValue(context, "");

            if (string.IsNullOrEmpty(password))
            {
                throw new LambdaException("No password supplied", args, context);
            }

            // Retrieving password rules from web.config, if any.
            var pwdRulesNode = new Node(".p5.config.get", "p5.auth.password-rules");
            var pwdRule      = context.RaiseEvent(".p5.config.get", pwdRulesNode) [0]?.Get(context, "");

            if (!string.IsNullOrEmpty(pwdRule))
            {
                // Verifying that specified password obeys by rules from web.config.
                Regex regex = new Regex(pwdRule);
                if (!regex.IsMatch(password))
                {
                    // New password was not accepted, throwing an exception.
                    args.FindOrInsert("password").Value = "xxx";
                    throw new LambdaSecurityException("Password didn't obey by your configuration settings, which are as follows; " + pwdRule, args, context);
                }
            }

            // Figuring out username of current context.
            string username = context.Ticket.Username;

            // Retrieving system salt before we enter write lock.
            var serverSalt = context.RaiseEvent(".p5.auth.get-server-salt").Get <string> (context);

            // Locking access to password file as we edit user object
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Changing user's password
                // Then salting password with user salt and system, before salting it with system salt
                var userPasswordFingerprint = context.RaiseEvent("p5.crypto.hash.create-sha256", new Node("", serverSalt + password)).Get <string> (context);
                authFile ["users"] [username] ["password"].Value = userPasswordFingerprint;
            });
        }
Esempio n. 14
0
        /*
         * Changes the GnuPG keypair for server.
         */
        public static void ChangeServerPGPKey(ApplicationContext context, string fingerprint, Node args)
        {
            // Verifying key exists, both its public key, and its private key.
            var result = context.RaiseEvent("p5.crypto.pgp-keys.public.list", new Node("p5.crypto.pgp-keys.public.list", fingerprint));

            if (result.FirstChild.Name != fingerprint)
            {
                throw new LambdaSecurityException("The specified new public key does not exist", args, context);
            }
            result = context.RaiseEvent("p5.crypto.pgp-keys.private.list", new Node("p5.crypto.pgp-keys.private.list", fingerprint));
            if (result.FirstChild.Name != fingerprint)
            {
                throw new LambdaSecurityException("The specified new public key does not exist", args, context);
            }

            // Changing key.
            AuthFile.ModifyAuthFile(context, delegate(Node node) {
                node [GnuPgpFingerprintNodeName].Value = fingerprint;
            });
        }
Esempio n. 15
0
        /*
         * Deletes the currently logged in user
         */
        public static void DeleteMyUser(ApplicationContext context, Node args)
        {
            // Retrieving username to delete.
            string username = context.Ticket.Username;

            // Deleting user's home directory
            context.Raise("p5.io.folder.delete", new Node("", "/users/" + username + "/"));

            // Locking access to password file as we delete user object
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Removing user
                authFile["users"][username].UnTie();
            });

            var def = CreateDefaultTicket(context);

            SetTicket(def);
            context.UpdateTicket(def);
        }
Esempio n. 16
0
        /*
         * Returns all access objects for system.
         */
        public static void DeleteAccess(ApplicationContext context, Node args)
        {
            // Locking access to password file as we create new access object.
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Verifying access rights exists.
                if (authFile ["access"] == null)
                {
                    return;
                }

                // Iterating all access objects passed in by caller.
                var access    = authFile ["access"];
                var delAccess = XUtil.Iterate <Node> (context, args).ToList();
                foreach (var idxAccess in delAccess)
                {
                    // Removing all matches.
                    access.Children.First(ix => ix.Name == idxAccess.Name && ix.Get(context, "") == idxAccess.GetExValue(context, "")).UnTie();
                }
            });
        }
        /*
         * Changes password of "root" account, but only if existing root account's password
         * is null. Used during setup of system
         */
        public static void SetRootPassword(ApplicationContext context, Node args)
        {
            // Retrieving password given.
            string password = args.GetExChildValue <string> ("password", context);

            // Retrieving password rules from web.config, if any.
            var pwdRulesNode = new Node(".p5.config.get", "p5.auth.password-rules");
            var pwdRule      = context.RaiseEvent(".p5.config.get", pwdRulesNode) [0]?.Get(context, "");

            if (!string.IsNullOrEmpty(pwdRule))
            {
                // Verifying that specified password obeys by rules from web.config.
                Regex regex = new Regex(pwdRule);
                if (!regex.IsMatch(password))
                {
                    // New password was not accepted, throwing an exception.
                    args.FindOrInsert("password").Value = "xxx";
                    throw new LambdaSecurityException("Password didn't obey by your configuration settings, which are as follows; " + pwdRule, args, context);
                }
            }

            // Creating root account.
            var rootAccountNode = new Node("", "root");

            rootAccountNode.Add("password", password);
            rootAccountNode.Add("role", "root");
            CreateUser(context, rootAccountNode);

            // Creating "guest account" section, which is needed for settings among other things.
            var guestAccountName = context.RaiseEvent(".p5.auth.get-default-context-username").Get <string> (context);

            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                authFile ["users"].Add(guestAccountName);
                authFile ["users"] ["guest"].Add("role", context.RaiseEvent(".p5.auth.get-default-context-role").Get <string> (context));
            });
        }
Esempio n. 18
0
        /*
         * Creates a new user.
         */
        public static void CreateUser(ApplicationContext context, Node args)
        {
            // Retrieving arguments.
            var username = args.GetExValue <string> (context);
            var password = args.GetExChildValue <string> ("password", context);
            var role     = args.GetExChildValue <string> ("role", context);

            // Sanity checking role name towards guest account name.
            if (role == context.RaiseEvent(".p5.auth.get-default-context-role").Get <string> (context))
            {
                throw new LambdaException("Sorry, but that's the name of our guest account role.", args, context);
            }

            // Sanity checking username towards guest account name.
            if (username == context.RaiseEvent(".p5.auth.get-default-context-username").Get <string> (context))
            {
                throw new LambdaException("Sorry, but that's the name of our guest account.", args, context);
            }

            // Making sure [password] never leaves method in case of an exception.
            args.FindOrInsert("password").Value = "xxx";

            // Retrieving password rules from web.config, if any.
            if (!Passwords.IsGoodPassword(context, password))
            {
                // New password was not accepted, throwing an exception.
                throw new LambdaSecurityException(
                          "Password didn't obey by your configuration settings, which are as follows; " +
                          Passwords.PasswordRuleDescription(context),
                          args,
                          context);
            }

            // Basic sanity check new user's data.
            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(role))
            {
                throw new LambdaException(
                          "User must have username as value, [password] and [role] at the very least",
                          args,
                          context);
            }

            // Verifying username is valid, since we'll need to create a folder for user.
            VerifyUsernameValid(username);

            // To reduce lock time of "auth" file, we execute Blow Fish hashing before we enter lock.
            password = Passwords.SaltAndHashPassword(context, password);

            // Locking access to password file as we create new user object.
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Checking if user exist from before.
                if (authFile ["users"] [username] != null)
                {
                    throw new LambdaException(
                        "Sorry, that [username] is already taken by another user in the system",
                        args,
                        context);
                }

                // Adding user.
                var userNode = authFile ["users"].Add(username).LastChild;

                // Salting and hashing password, before storing it in "auth" file.
                userNode.Add("password", password);

                // Adding user to specified role.
                userNode.Add("role", role);

                // Adding all other specified objects to user.
                userNode.AddRange(args.Children.Where(ix => ix.Name != "password" && ix.Name != "role").Select(ix => ix.Clone()));
            });

            // Creating newly created user's directory structure.
            CreateUserDirectory(context, username);
        }
        /*
         * Creates a new user
         */
        public static void CreateUser(ApplicationContext context, Node args)
        {
            // Retrieving arguments.
            string username = args.GetExValue <string> (context);
            string password = args.GetExChildValue <string> ("password", context);
            string role     = args.GetExChildValue <string> ("role", context);

            // Sanity checking role name towards guest account name.
            if (role == context.RaiseEvent(".p5.auth.get-default-context-role").Get <string> (context))
            {
                throw new LambdaException("Sorry, but that's the name of our guest account role.", args, context);
            }

            // Sanity checking username towards guest account name.
            if (username == context.RaiseEvent(".p5.auth.get-default-context-username").Get <string> (context))
            {
                throw new LambdaException("Sorry, but that's the name of our guest account.", args, context);
            }

            // Making sure [password] never leaves method.
            args.FindOrInsert("password").Value = "xxx";

            // Retrieving password rules from web.config, if any.
            var pwdRulesNode = new Node(".p5.config.get", "p5.auth.password-rules");
            var pwdRule      = context.RaiseEvent(".p5.config.get", pwdRulesNode) [0]?.Get(context, "");

            if (!string.IsNullOrEmpty(pwdRule))
            {
                // Verifying that specified password obeys by rules from web.config.
                Regex regex = new Regex(pwdRule);
                if (!regex.IsMatch(password))
                {
                    // New password was not accepted, throwing an exception.
                    args.FindOrInsert("password").Value = "xxx";
                    throw new LambdaSecurityException("Password didn't obey by your configuration settings, which are as follows; " + pwdRule, args, context);
                }
            }

            // Basic sanity check.
            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(role))
            {
                throw new LambdaException(
                          "User must have username as value, [password] and [role] at the very least",
                          args,
                          context);
            }

            // Verifying username is valid, since we'll need to create a folder for user.
            VerifyUsernameValid(username);

            // Retrieving system salt before we enter write lock.
            var serverSalt = context.RaiseEvent(".p5.auth.get-server-salt").Get <string> (context);

            // Then salting user's password.
            var userPasswordFingerprint = context.RaiseEvent("p5.crypto.hash.create-sha256", new Node("", serverSalt + password)).Get <string> (context);

            // Locking access to password file as we create new user object.
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Checking if user exist from before.
                if (authFile ["users"] [username] != null)
                {
                    throw new LambdaException(
                        "Sorry, that [username] is already taken by another user in the system",
                        args,
                        context);
                }

                // Adding user.
                authFile ["users"].Add(username);

                // Creates a salt and password for user.
                authFile ["users"].LastChild.Add("password", userPasswordFingerprint);

                // Adding user to specified role.
                authFile ["users"].LastChild.Add("role", role);

                // Adding all other specified objects to user.
                foreach (var idxNode in args.Children.Where(ix => ix.Name != "username" && ix.Name != "password" && ix.Name != "role"))
                {
                    // Only adding nodes with some sort of actual value.
                    if (idxNode.Value != null || idxNode.Count > 0)
                    {
                        authFile ["users"].LastChild.Add(idxNode.Clone());
                    }
                }
            });

            // Creating newly created user's directory structure.
            CreateUserDirectory(context.RaiseEvent(".p5.core.application-folder").Get <string> (context), username);
        }
Esempio n. 20
0
        /*
         * Creates a new user
         */
        public static void CreateUser(ApplicationContext context, Node args)
        {
            string username = args.GetExValue <string>(context);
            string password = args.GetExChildValue <string>("password", context);
            string role     = args.GetExChildValue <string>("role", context);

            // Making sure [password] never leaves method, in case of exceptions
            args.FindOrInsert("password").Value = "xxx";

            // Basic syntax checking
            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(role))
            {
                throw new LambdaException(
                          "User must have [username], [password] and [role] at the very least",
                          args,
                          context);
            }

            // Verifying username is valid, since we'll need to create a folder for user
            VerifyUsernameValid(username);

            // Creating user salt, and retrieving system salt
            var serverSalt = context.Raise(".p5.auth.get-server-salt").Get <string> (context);

            // Then salting password with user salt, before salting it with system salt
            var userPasswordFingerprint = context.Raise("p5.crypto.hash.create-sha256", new Node("", serverSalt + password)).Get <string> (context);

            // Locking access to password file as we create new user object
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Checking if user exist from before
                if (authFile["users"][username] != null)
                {
                    throw new LambdaException(
                        "Sorry, that [username] is already taken by another user in the system",
                        args,
                        context);
                }

                // Adding user
                authFile["users"].Add(username);

                // Creates a salt and password for user
                authFile ["users"].LastChild.Add("password", userPasswordFingerprint);

                // Adding user to specified role
                authFile ["users"].LastChild.Add("role", role);

                // Adding all other specified objects to user
                foreach (var idxNode in args.Children.Where(ix => ix.Name != "username" && ix.Name != "password" && ix.Name != "role"))
                {
                    // Only adding nodes with some sort of actual value
                    if (idxNode.Value != null || idxNode.Children.Count > 0)
                    {
                        authFile["users"].LastChild.Add(idxNode.Clone());
                    }
                }
            });

            // Creating newly created user's directory structure
            CreateUserDirectory(context.Raise(".p5.core.application-folder").Get <string>(context), username);
        }
        /*
         * Edits an existing user
         */
        public static void EditUser(ApplicationContext context, Node args)
        {
            // Retrieving username, and sanity checking invocation.
            string username = args.GetExValue <string> (context);

            if (args ["username"] != null)
            {
                throw new LambdaSecurityException("Cannot change username for user", args, context);
            }

            // Retrieving new password and role, defaulting to null, which will not update existing values.
            string newPassword = args.GetExChildValue <string> ("password", context);
            string newRole     = args.GetExChildValue <string> ("role", context);

            // Sanity checking role name towards guest account name.
            if (newRole == context.RaiseEvent(".p5.auth.get-default-context-role").Get <string> (context))
            {
                throw new LambdaException("Sorry, but that's the name of our guest account role.", args, context);
            }

            // Retrieving password rules from web.config, if any.
            // But only if a new password was given.
            if (!string.IsNullOrEmpty(newPassword))
            {
                // Verifying password conforms to password rules.
                var pwdRulesNode = new Node(".p5.config.get", "p5.auth.password-rules");
                var pwdRule      = context.RaiseEvent(".p5.config.get", pwdRulesNode) [0]?.Get(context, "");
                if (!string.IsNullOrEmpty(pwdRule))
                {
                    // Verifying that specified password obeys by rules from web.config.
                    Regex regex = new Regex(pwdRule);
                    if (!regex.IsMatch(newPassword))
                    {
                        // New password was not accepted, throwing an exception.
                        args.FindOrInsert("password").Value = "xxx";
                        throw new LambdaSecurityException("Password didn't obey by your configuration settings, which are as follows; " + pwdRule, args, context);
                    }
                }
            }

            // Retrieving system salt before we enter write lock. (important, since otherwise we'd have a deadlock condition here).
            var serverSalt = newPassword == null ? null : context.RaiseEvent(".p5.auth.get-server-salt").Get <string> (context);

            // Locking access to password file as we edit user object.
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Checking to see if user exist.
                if (authFile ["users"] [username] == null)
                {
                    throw new LambdaException(
                        "Sorry, that user does not exist",
                        args,
                        context);
                }

                // Updating user's password, but only if a new password was supplied by caller.
                if (!string.IsNullOrEmpty(newPassword))
                {
                    // Making sure we salt password with system salt, before we create our SHA256 value, which is what we actually store in our "auth" file.
                    var userPasswordFingerprint = context.RaiseEvent("p5.crypto.hash.create-sha256", new Node("", serverSalt + newPassword)).Get <string> (context);
                    authFile ["users"] [username] ["password"].Value = userPasswordFingerprint;
                }

                // Updating user's role, if a new role was supplied by caller.
                if (newRole != null)
                {
                    authFile ["users"] [username] ["role"].Value = newRole;
                }

                // Checking if caller wants to edit settings.
                if (args.Name == "p5.auth.users.edit")
                {
                    // Removing old settings.
                    authFile ["users"] [username].RemoveAll(ix => ix.Name != "password" && ix.Name != "role");

                    // Adding all other specified objects to user.
                    foreach (var idxNode in args.Children.Where(ix => ix.Name != "password" && ix.Name != "role"))
                    {
                        authFile ["users"] [username].Add(idxNode.Clone());
                    }
                }
            });
        }
Esempio n. 22
0
        /*
         * Edits an existing user.
         */
        public static void EditUser(ApplicationContext context, Node args)
        {
            // Retrieving username, and sanity checking invocation.
            var username = args.GetExValue <string> (context);

            if (args ["username"] != null)
            {
                throw new LambdaSecurityException("Cannot change username for user", args, context);
            }

            // Retrieving new password and role, defaulting to null, which will not update existing values.
            var password = args.GetExChildValue <string> ("password", context, null);
            var role     = args.GetExChildValue <string> ("role", context, null);

            // Sanity checking role name towards guest account name.
            if (role == context.RaiseEvent(".p5.auth.get-default-context-role").Get <string> (context))
            {
                throw new LambdaException("Sorry, but that's the name of your system's guest account role.", args, context);
            }

            // Changing user's password, but only if a [password] argument was explicitly supplied by caller.
            if (!string.IsNullOrEmpty(password))
            {
                // Verifying password conforms to password rules.
                if (!Passwords.IsGoodPassword(context, password))
                {
                    // New password was not accepted, throwing an exception.
                    args.FindOrInsert("password").Value = "xxx";
                    var description = Passwords.PasswordRuleDescription(context);
                    throw new LambdaSecurityException("Password didn't obey by your configuration settings, which are as follows; " + description, args, context);
                }
            }

            // To reduce lock time of "auth" file we execute Blow Fish hashing before we enter lock.
            password = password == null ? null : Passwords.SaltAndHashPassword(context, password);

            // Locking access to password file as we edit user object.
            AuthFile.ModifyAuthFile(
                context,
                delegate(Node authFile) {
                // Checking to see if user exist.
                if (authFile ["users"] [username] == null)
                {
                    throw new LambdaException(
                        "Sorry, that user does not exist",
                        args,
                        context);
                }

                // Updating user's password, but only if a new password was supplied by caller.
                if (!string.IsNullOrEmpty(password))
                {
                    authFile ["users"] [username] ["password"].Value = password;
                }

                // Updating user's role, if a new role was supplied by caller.
                if (role != null)
                {
                    authFile ["users"] [username] ["role"].Value = role;
                }

                // Checking if caller wants to edit settings.
                if (args.Name == "p5.auth.users.edit")
                {
                    // Removing old settings.
                    authFile ["users"] [username].RemoveAll(ix => ix.Name != "password" && ix.Name != "role" && ix.Name != "salt");

                    // Adding all other specified objects to user.
                    foreach (var idxNode in args.Children.Where(ix => ix.Name != "password" && ix.Name != "role" && ix.Name != "salt"))
                    {
                        authFile ["users"] [username].Add(idxNode.Clone());
                    }
                }
            });
        }