% PasswordProvider for use by SPFMJSCredentialHandler

% Copyright 2020-2021 The MathWorks, Inc.

classdef MJSCredentialHandlerPasswordProvider < parallel.internal.cluster.PasswordProvider
    
    properties (Access = private)
        % Map of all passwords this provider can automatically offer
        Passwords
        
        % Map of all passwords this provider can automatically offer
        % for change password operations
        ChangePasswords
        
        % How long the test user requests the passwords to be cached for
        RememberPassword
        
        % If true, error if promptForIdentity is called. This is to handle
        % the case where we try and perform an operation as a user which
        % does not exist, and would rather error than automatically
        % create that user.
        ErrorOnPromptForIdentity
    end
    
    % NB: This class should only be used by SPFMJSCredentialHandler
    methods (Access = ?parallel.internal.cluster.SPFMJSCredentialHandler)
        function obj = MJSCredentialHandlerPasswordProvider(errorOnPromptForIdentity)
            obj.Passwords = containers.Map();
            obj.ChangePasswords = containers.Map();
            obj.RememberPassword = parallel.internal.types.RememberPassword.Session;
            obj.ErrorOnPromptForIdentity = errorOnPromptForIdentity;
        end
        
        % Puts the given username and password into the map of passwords
        % this provider can offer
        function put(obj, username, password)
            obj.Passwords(username) = password;
        end
        
        % Puts the given username and password into the map of change
        % passwords this provider can offer for change password operations
        function putPasswordForChange(obj, username, password)
            obj.ChangePasswords(username) = password;
        end
        
        % Sets how long passwords offered by this provider should be
        % remembered
        function setRememberPassword(obj, rememberPassword)
            obj.RememberPassword = rememberPassword;
        end
    end
    
    % PasswordProvider methods
    methods
        function setPromptForPassword(~, ~)
            % Do nothing
        end
        
        function promptForPassword = getPromptForPassword(~)
            promptForPassword = true;
        end
        
        function username = promptForIdentity(obj, suggestedUserName, ~)
            if obj.ErrorOnPromptForIdentity
                error(message('parallel:cluster:mjs:UnknownUser', suggestedUserName));
            end
            username = suggestedUserName;
        end
        
        function promptForCurrentPassword(~, ~, ~, ~)
            % Do nothing
        end
        
        function promptForNewPassword(~, ~, ~, ~)
            % Do nothing
        end
        
        function promptForChangePassword(~, ~, ~, ~, ~, ~)
            % Do nothing
        end
       
        function username = promptForTemporaryUserSwitch(~, ~, ~, ~, ~, ~) %#ok<STOUT>
            assert(false, 'Unsupported method');
        end
        
        function promptForAdminPassword(~, ~, ~, ~)
            assert(false, 'Unsupported method');
        end
        
        function issueNotOwnerWarning(~, ~, ~)
            assert(false, 'Unsupported method');
        end
        
        function encryptedBytes = fetchEncryptedPassword(obj, encryptor, stringEncoder, username)
            encryptedBytes = encryptor.encrypt(stringEncoder.encode(obj.Passwords(username)));
        end
        
        function [hashedBytes, rememberPassword] = fetchHashedPassword(obj, hasher, stringEncoder, username)
            hashedBytes = hasher.digest(stringEncoder.encode(obj.Passwords(username)));
            rememberPassword = obj.RememberPassword;
        end
        
        function hashedBytes = fetchHashedChangePassword(obj, hasher, stringEncoder, username)
            hashedBytes = hasher.digest(stringEncoder.encode(obj.ChangePasswords(username)));
        end
        
        function clear(~)
            % Do nothing
        end
    end
end
