summaryrefslogtreecommitdiffstats
path: root/gluster/swift/common/middleware/gswauth/swauth/authtypes.py
blob: fbf532d9223dbac9a74ae223d576e8588bc0f104 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Pablo Llopis 2011


"""
This module hosts available auth types for encoding and matching user keys.
For adding a new auth type, simply write a class that satisfies the following
conditions:

- For the class name, capitalize first letter only. This makes sure the user
  can specify an all-lowercase config option such as "plaintext" or "sha1".
  Swauth takes care of capitalizing the first letter before instantiating it.
- Write an encode(key) method that will take a single argument, the user's key,
  and returns the encoded string. For plaintext, this would be
  "plaintext:<key>"
- Write a match(key, creds) method that will take two arguments: the user's
  key, and the user's retrieved credentials. Return a boolean value that
  indicates whether the match is True or False.

Note that, since some of the encodings will be hashes, swauth supports the
notion of salts. Thus, self.salt will be set to either a user-specified salt
value or to a default value.
"""

import hashlib
import os


#: Maximum length any valid token should ever be.
MAX_TOKEN_LENGTH = 5000


class Plaintext(object):
    """
    Provides a particular auth type for encoding format for encoding and
    matching user keys.

    This class must be all lowercase except for the first character, which
    must be capitalized. encode and match methods must be provided and are
    the only ones that will be used by swauth.
    """
    def encode(self, key):
        """
        Encodes a user key into a particular format. The result of this method
        will be used by swauth for storing user credentials.

        :param key: User's secret key
        :returns: A string representing user credentials
        """
        return "plaintext:%s" % key

    def match(self, key, creds):
        """
        Checks whether the user-provided key matches the user's credentials

        :param key: User-supplied key
        :param creds: User's stored credentials
        :returns: True if the supplied key is valid, False otherwise
        """
        return self.encode(key) == creds


class Sha1(object):
    """
    Provides a particular auth type for encoding format for encoding and
    matching user keys.

    This class must be all lowercase except for the first character, which
    must be capitalized. encode and match methods must be provided and are
    the only ones that will be used by swauth.
    """

    def encode_w_salt(self, salt, key):
        """
        Encodes a user key with salt into a particular format. The result of
        this method will be used internally.

        :param salt: Salt for hashing
        :param key: User's secret key
        :returns: A string representing user credentials
        """
        enc_key = '%s%s' % (salt, key)
        enc_val = hashlib.sha1(enc_key).hexdigest()
        return "sha1:%s$%s" % (salt, enc_val)

    def encode(self, key):
        """
        Encodes a user key into a particular format. The result of this method
        will be used by swauth for storing user credentials.

        :param key: User's secret key
        :returns: A string representing user credentials
        """
        salt = self.salt or os.urandom(32).encode('base64').rstrip()
        return self.encode_w_salt(salt, key)

    def match(self, key, creds):
        """
        Checks whether the user-provided key matches the user's credentials

        :param key: User-supplied key
        :param creds: User's stored credentials
        :returns: True if the supplied key is valid, False otherwise
        """

        type, rest = creds.split(':')
        salt, enc = rest.split('$')

        return self.encode_w_salt(salt, key) == creds


class Sha512(object):
    """
    Provides a particular auth type for encoding format for encoding and
    matching user keys.

    This class must be all lowercase except for the first character, which
    must be capitalized. encode and match methods must be provided and are
    the only ones that will be used by swauth.
    """

    def encode_w_salt(self, salt, key):
        """
        Encodes a user key with salt into a particular format. The result of
        this method will be used internal.

        :param salt: Salt for hashing
        :param key: User's secret key
        :returns: A string representing user credentials
        """
        enc_key = '%s%s' % (salt, key)
        enc_val = hashlib.sha512(enc_key).hexdigest()
        return "sha512:%s$%s" % (salt, enc_val)

    def encode(self, key):
        """
        Encodes a user key into a particular format. The result of this method
        will be used by swauth for storing user credentials.

        If salt is not manually set in conf file, a random salt will be
        generated and used.

        :param key: User's secret key
        :returns: A string representing user credentials
        """
        salt = self.salt or os.urandom(32).encode('base64').rstrip()
        return self.encode_w_salt(salt, key)

    def match(self, key, creds):
        """Checks whether the user-provided key matches the user's credentials

        :param key: User-supplied key
        :param creds: User's stored credentials
        :returns: True if the supplied key is valid, False otherwise
        """

        type, rest = creds.split(':')
        salt, enc = rest.split('$')

        return self.encode_w_salt(salt, key) == creds