{"id":1062,"date":"2019-07-27T20:11:16","date_gmt":"2019-07-27T19:11:16","guid":{"rendered":"http:\/\/coding.moris.org\/?p=1062"},"modified":"2025-10-11T22:39:55","modified_gmt":"2025-10-11T21:39:55","slug":"so-question-57225262-inputting-list-of-passwords-in-a-class","status":"publish","type":"post","link":"https:\/\/priscimon.net\/coding\/2019\/07\/27\/so-question-57225262-inputting-list-of-passwords-in-a-class\/","title":{"rendered":"SO #57225262\u2013Inputting list of passwords in a class"},"content":{"rendered":"\n<p><a href=\"https:\/\/stackoverflow.com\/questions\/57225262\/inputting-list-of-passwords-in-a-class\"><em>Stack Overflow<\/em> question &#8216;Inputting list of passwords in a class&#8217;<\/a> is more interesting as an object-oriented design (OOD) exercise than as a debugging exercise, but it also provides an opportunity to practise some Python programming.<\/p>\n\n\n\n<p>The requirements identified in the problem are:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>represent a set of credentials comprised of a username and a password;<\/li><li>represent a user account made up of an identifier and one active set of credentials and zero or more inactive credentials;<\/li><li>store user accounts that can be retrieved subsequently by username;<\/li><li>validate a given set of credentials, using the stored user accounts.<\/li><\/ul>\n\n\n\n<p>Additionally, a user account has the following constraints:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>It must be uniquely identifiable by the username of the active set of credentials.<\/li><li>A set of credentials must be used only once for a given user account.<\/li><\/ul>\n\n\n\n<p>The design model consists of multiple classes, each addressing a single responsibility as follows.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Class<\/th><th>Responsibility<\/th><\/tr><\/thead><tbody><tr><td><code>Credentials<\/code><\/td><td>represent a set of credentials<\/td><\/tr><tr><td><code>UserAccount<\/code><\/td><td>represent a user account<\/td><\/tr><tr><td><code>AccountStore<\/code><\/td><td>store user accounts, enforcing the uniqueness constraint<\/td><\/tr><tr><td><code>Authentication<\/code><\/td><td>validate supplied credentials<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>The <a href=\"#listing\">program code<\/a> implements the model very faithfully and uses the same class names, thus making it easy to reason about. It has been <a href=\"#output\">tested with Python 2.7.15rc1<\/a> and has been checked for <a href=\"https:\/\/www.python.org\/dev\/peps\/pep-0008\/\">PEP8<\/a> compliance.<\/p>\n\n\n\n<blockquote><h5>NOTES<\/h5><p>For brevity, the solution presented here does not:<\/p><ul>\n<li>implement best practices used for security in real-world scenarios, such as salting and hashing;<\/li>\n<li>enforce uniqueness of user account identifiers;<\/li>\n<li>consider performance factors.<\/li>\n<\/ul><p>In lieu of conventional unit tests, a main routine exercises use-cases to ensure that the program works properly.<\/p><\/blockquote>\n\n\n\n<p><a name=\"listing\"><\/a><\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>class Credentials:\n\n    def __init__(self, username, password):\n        self.username = username\n        self.password = password\n\n    def has_username(self, username):\n        return self.username == username\n\n    def matches(self, credentials):\n        return self.username == credentials.username and \\\n            self.password == credentials.password\n\nclass UserAccount:\n\n    def __init__(self, user_id):\n        self.user_id = user_id\n        self.active_credentials = None\n        self.past_credentials = &#91;]\n\n    def add(self, credentials):\n        self._check_uniqueness(credentials)\n        if self.active_credentials is None:\n            self.active_credentials = credentials\n        else:\n            self.past_credentials.append(self.active_credentials)\n            self.active_credentials = credentials\n\n    def has_username(self, username):\n        return self.active_credentials.has_username(username)\n\n    def has_same_username(self, user_account):\n        return self.has_username(user_account.active_credentials.username)\n\n    def has_credentials(self, credentials):\n        return self.active_credentials is not None and \\\n            self.active_credentials.matches(credentials)\n\n    def _check_uniqueness(self, credentials):\n        if self.has_credentials(credentials):\n            raise Exception('These credentials are currently in use.')\n        for c in self.past_credentials:\n            if c.matches(credentials):\n                raise Exception(\n                        'These credentials have been used in the past.')\n\nclass AccountStore:\n\n    def __init__(self):\n        self.user_accounts = &#91;]\n\n    def add(self, user_account):\n        self._check_uniqueness(user_account)\n        self.user_accounts.append(user_account)\n\n    def find_by_username(self, username):\n        for ua in self.user_accounts:\n            if ua.has_username(username):\n                return ua\n        return None\n\n    def _check_uniqueness(self, user_account):\n        for ua in self.user_accounts:\n            if ua.has_same_username(user_account):\n                raise Exception(\n                        'An account with the same username is already active.')\n\nclass Authentication:\n\n    def __init__(self, account_store):\n        self.account_store = account_store\n\n    def validate(self, credentials):\n        user_account = self.account_store.find_by_username(\n                credentials.username)\n        if user_account is None:\n            return False\n        return user_account.has_credentials(credentials)\n\nif __name__ == '__main__':\n    credentials = Credentials('user1', 'password1')\n    user_account = UserAccount(101)\n    user_account.add(credentials)\n\n    account_store = AccountStore()\n    account_store.add(user_account)\n\n    user_account1 = account_store.find_by_username('user1')\n    print 'user_account1', user_account1\n\n    user_account2 = account_store.find_by_username('user2')\n    print 'user_account2', user_account2\n\n    authentication = Authentication(account_store)\n    print 'Expecting True...', authentication.validate(\n            Credentials('user1', 'password1'))\n    print 'Expecting False...', authentication.validate(\n            Credentials('user2', 'password1'))\n    print 'Expecting False...', authentication.validate(\n            Credentials('user1', 'password2'))\n\n    user_account.add(Credentials('user1', 'password2'))\n    print 'Expecting True...', authentication.validate(\n            Credentials('user1', 'password2'))\n    print 'Expecting False...', authentication.validate(\n            Credentials('user1', 'password1'))\n\n    try:\n        user_account.add(Credentials('user1', 'password1'))\n    except Exception:\n        print 'Expecting exception... Pass'\n\n    try:\n        user_account.add(Credentials('user2', 'password1'))\n        print 'Not expecting exception... Pass'\n        print 'Expecting True...', authentication.validate(\n                Credentials('user2', 'password1'))\n    except Exception:\n        print 'Not expecting exception... Fail'\n\n    try:\n        user_account1 = UserAccount(102)\n        user_account1.add(Credentials('user1', 'whatever'))\n        account_store.add(user_account1)\n        print 'Expecting True...', authentication.validate(\n                Credentials('user1', 'whatever'))\n    except Exception:\n        print 'Not expecting exception... Fail'\n\n    try:\n        user_account2 = UserAccount(103)\n        user_account2.add(Credentials('user1', 'whatever'))\n        account_store.add(user_account1)\n        print 'Expecting exception... Fail'\n    except Exception:\n        print 'Expecting exception... Pass'\n\n<\/code><\/pre>\n\n\n\n<p><a name=\"output\"><\/a><br \/>The output of the program is:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>EY@LENNY:~\/Source\/junk\/python\/pwman$ python all.py\nuser_account1 &lt;__main__.UserAccount instance at 0x7faa36f11170&gt;\nuser_account2 None\nExpecting True... True\nExpecting False... False\nExpecting False... False\nExpecting True... True\nExpecting False... False\nExpecting exception... Pass\nNot expecting exception... Pass\nExpecting True... True\nExpecting True... True\nExpecting exception... Pass\nEY@LENNY:~\/Source\/junk\/python\/pwman$\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Stack Overflow question &#8216;Inputting list of passwords in a class&#8217; is more interesting as an object-oriented design (OOD) exercise than as a debugging exercise, but it also provides an opportunity to practise some Python programming. The requirements identified in the problem are: represent a set of credentials comprised of a username and a password; represent [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1062","post","type-post","status-publish","format-standard","hentry","category-general"],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3I4g9-h8","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/priscimon.net\/coding\/wp-json\/wp\/v2\/posts\/1062","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/priscimon.net\/coding\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/priscimon.net\/coding\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/priscimon.net\/coding\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/priscimon.net\/coding\/wp-json\/wp\/v2\/comments?post=1062"}],"version-history":[{"count":65,"href":"https:\/\/priscimon.net\/coding\/wp-json\/wp\/v2\/posts\/1062\/revisions"}],"predecessor-version":[{"id":1946,"href":"https:\/\/priscimon.net\/coding\/wp-json\/wp\/v2\/posts\/1062\/revisions\/1946"}],"wp:attachment":[{"href":"https:\/\/priscimon.net\/coding\/wp-json\/wp\/v2\/media?parent=1062"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/priscimon.net\/coding\/wp-json\/wp\/v2\/categories?post=1062"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/priscimon.net\/coding\/wp-json\/wp\/v2\/tags?post=1062"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}