Merge tag '0.4.0' into debian/mitaka
castellan 0.4.0 release
Thomas Goirand
8 years ago
0 | include AUTHORS | |
1 | include ChangeLog | |
2 | exclude .gitignore | |
3 | exclude .gitreview | |
4 | ||
5 | global-exclude *.pyc |
0 | # Copyright (c) IBM | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | ||
15 | """ | |
16 | Base Credential Object Class | |
17 | ||
18 | This module defines the Credential class. The Credential class is the base | |
19 | class to represent all credentials which a KeyMaster can use for | |
20 | authenticating. | |
21 | """ | |
22 | ||
23 | import abc | |
24 | ||
25 | import six | |
26 | ||
27 | ||
28 | @six.add_metaclass(abc.ABCMeta) | |
29 | class Credential(object): | |
30 | """Base class to represent all credentials.""" | |
31 | ||
32 | def __init__(self): | |
33 | pass |
0 | # Copyright (c) 2015 IBM | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | """ | |
15 | Keystone Password Credential | |
16 | ||
17 | This module defines the Keystone Password credential. | |
18 | """ | |
19 | from castellan.common.credentials import password | |
20 | ||
21 | ||
22 | class KeystonePassword(password.Password): | |
23 | """This class represents a keystone password credential.""" | |
24 | ||
25 | def __init__(self, password, username=None, user_id=None, | |
26 | user_domain_id=None, user_domain_name=None, trust_id=None, | |
27 | domain_id=None, domain_name=None, project_id=None, | |
28 | project_name=None, project_domain_id=None, | |
29 | project_domain_name=None, reauthenticate=True): | |
30 | """Create a new Keystone Password Credential. | |
31 | ||
32 | :param string password: Password for authentication. | |
33 | :param string username: Username for authentication. | |
34 | :param string user_id: User ID for authentication. | |
35 | :param string user_domain_id: User's domain ID for authentication. | |
36 | :param string user_domain_name: User's domain name for authentication. | |
37 | :param string trust_id: Trust ID for trust scoping. | |
38 | :param string domain_id: Domain ID for domain scoping. | |
39 | :param string domain_name: Domain name for domain scoping. | |
40 | :param string project_id: Project ID for project scoping. | |
41 | :param string project_name: Project name for project scoping. | |
42 | :param string project_domain_id: Project's domain ID for project. | |
43 | :param string project_domain_name: Project's domain name for project. | |
44 | :param bool reauthenticate: Allow fetching a new token if the current | |
45 | one is going to expire. (optional) default True | |
46 | """ | |
47 | ||
48 | self._user_id = user_id | |
49 | self._user_domain_id = user_domain_id | |
50 | self._user_domain_name = user_domain_name | |
51 | self._trust_id = trust_id | |
52 | self._domain_id = domain_id | |
53 | self._domain_name = domain_name | |
54 | self._project_id = project_id | |
55 | self._project_name = project_name | |
56 | self._project_domain_id = project_domain_id | |
57 | self._project_domain_name = project_domain_name | |
58 | self._reauthenticate = reauthenticate | |
59 | ||
60 | super(KeystonePassword, self).__init__(username, | |
61 | password) | |
62 | ||
63 | @property | |
64 | def user_id(self): | |
65 | """This method returns a user_id.""" | |
66 | return self._user_id | |
67 | ||
68 | @property | |
69 | def user_domain_id(self): | |
70 | """This method returns a user_domain_id.""" | |
71 | return self._user_domain_id | |
72 | ||
73 | @property | |
74 | def user_domain_name(self): | |
75 | """This method returns a user_domain_name.""" | |
76 | return self._user_domain_name | |
77 | ||
78 | @property | |
79 | def trust_id(self): | |
80 | """This method returns a trust_id.""" | |
81 | return self._trust_id | |
82 | ||
83 | @property | |
84 | def domain_id(self): | |
85 | """This method returns a domain_id.""" | |
86 | return self._domain_id | |
87 | ||
88 | @property | |
89 | def domain_name(self): | |
90 | """This method returns a domain_name.""" | |
91 | return self._domain_name | |
92 | ||
93 | @property | |
94 | def project_id(self): | |
95 | """This method returns a project_id.""" | |
96 | return self._project_id | |
97 | ||
98 | @property | |
99 | def project_name(self): | |
100 | """This method returns a project_name.""" | |
101 | return self._project_name | |
102 | ||
103 | @property | |
104 | def project_domain_id(self): | |
105 | """This method returns a project_domain_id.""" | |
106 | return self._project_domain_id | |
107 | ||
108 | @property | |
109 | def project_domain_name(self): | |
110 | """This method returns a project_domain_name.""" | |
111 | return self._project_domain_name | |
112 | ||
113 | @property | |
114 | def reauthenticate(self): | |
115 | """This method returns reauthenticate.""" | |
116 | return self._reauthenticate | |
117 | ||
118 | def __eq__(self, other): | |
119 | if isinstance(other, KeystonePassword): | |
120 | return ( | |
121 | self._password == other._password and | |
122 | self._username == other._username and | |
123 | self._user_id == other._user_id and | |
124 | self._user_domain_id == other._user_domain_id and | |
125 | self._user_domain_name == other._user_domain_name and | |
126 | self._trust_id == other._trust_id and | |
127 | self._domain_id == other._domain_id and | |
128 | self._domain_name == other._domain_name and | |
129 | self._project_id == other._project_id and | |
130 | self._project_name == other._project_name and | |
131 | self._project_domain_id == other._project_domain_id and | |
132 | self._project_domain_name == other._project_domain_name and | |
133 | self._reauthenticate == other._reauthenticate) | |
134 | else: | |
135 | return False | |
136 | ||
137 | def __ne__(self, other): | |
138 | result = self.__eq__(other) | |
139 | return not result |
0 | # Copyright (c) 2015 IBM | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | """ | |
15 | Keystone Token Credential | |
16 | ||
17 | This module defines the Keystone Token credential. | |
18 | """ | |
19 | from castellan.common.credentials import token | |
20 | ||
21 | ||
22 | class KeystoneToken(token.Token): | |
23 | """This class represents a keystone token credential.""" | |
24 | ||
25 | def __init__(self, token, trust_id=None, domain_id=None, domain_name=None, | |
26 | project_id=None, project_name=None, project_domain_id=None, | |
27 | project_domain_name=None, reauthenticate=True): | |
28 | """Create a new Keystone Token Credential. | |
29 | ||
30 | :param string token: Token for authentication. The type of token | |
31 | formats accepted are UUID, PKI, and Fernet. | |
32 | :param string trust_id: Trust ID for trust scoping. | |
33 | :param string domain_id: Domain ID for domain scoping. | |
34 | :param string domain_name: Domain name for domain scoping. | |
35 | :param string project_id: Project ID for project scoping. | |
36 | :param string project_name: Project name for project scoping. | |
37 | :param string project_domain_id: Project's domain ID for project. | |
38 | :param string project_domain_name: Project's domain name for project. | |
39 | :param bool reauthenticate: Allow fetching a new token if the current | |
40 | one is going to expire. (optional) default True | |
41 | """ | |
42 | ||
43 | self._trust_id = trust_id | |
44 | self._domain_id = domain_id | |
45 | self._domain_name = domain_name | |
46 | self._project_id = project_id | |
47 | self._project_name = project_name | |
48 | self._project_domain_id = project_domain_id | |
49 | self._project_domain_name = project_domain_name | |
50 | self._reauthenticate = reauthenticate | |
51 | ||
52 | super(KeystoneToken, self).__init__(token) | |
53 | ||
54 | @property | |
55 | def trust_id(self): | |
56 | """This method returns a trust_id.""" | |
57 | return self._trust_id | |
58 | ||
59 | @property | |
60 | def domain_id(self): | |
61 | """This method returns a domain_id.""" | |
62 | return self._domain_id | |
63 | ||
64 | @property | |
65 | def domain_name(self): | |
66 | """This method returns a domain_name.""" | |
67 | return self._domain_name | |
68 | ||
69 | @property | |
70 | def project_id(self): | |
71 | """This method returns a project_id.""" | |
72 | return self._project_id | |
73 | ||
74 | @property | |
75 | def project_name(self): | |
76 | """This method returns a project_name.""" | |
77 | return self._project_name | |
78 | ||
79 | @property | |
80 | def project_domain_id(self): | |
81 | """This method returns a project_domain_id.""" | |
82 | return self._project_domain_id | |
83 | ||
84 | @property | |
85 | def project_domain_name(self): | |
86 | """This method returns a project_domain_name.""" | |
87 | return self._project_domain_name | |
88 | ||
89 | @property | |
90 | def reauthenticate(self): | |
91 | """This method returns reauthenticate.""" | |
92 | return self._reauthenticate | |
93 | ||
94 | def __eq__(self, other): | |
95 | if isinstance(other, KeystoneToken): | |
96 | return ( | |
97 | self._token == other._token and | |
98 | self._trust_id == other._trust_id and | |
99 | self._domain_id == other._domain_id and | |
100 | self._domain_name == other._domain_name and | |
101 | self._project_id == other._project_id and | |
102 | self._project_name == other._project_name and | |
103 | self._project_domain_id == other._project_domain_id and | |
104 | self._project_domain_name == other._project_domain_name and | |
105 | self._reauthenticate == other._reauthenticate) | |
106 | else: | |
107 | return False | |
108 | ||
109 | def __ne__(self, other): | |
110 | result = self.__eq__(other) | |
111 | return not result |
0 | # Copyright (c) 2015 IBM | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | """ | |
15 | Base Password Credential | |
16 | ||
17 | This module defines the Password credential. | |
18 | """ | |
19 | ||
20 | from castellan.common.credentials import credential | |
21 | ||
22 | ||
23 | class Password(credential.Credential): | |
24 | """This class represents a password credential.""" | |
25 | ||
26 | def __init__(self, username, password): | |
27 | """Create a new Password credential. | |
28 | ||
29 | :param string password: Password for authentication. | |
30 | :param string username: Username for authentication. | |
31 | """ | |
32 | ||
33 | self._username = username | |
34 | self._password = password | |
35 | ||
36 | @property | |
37 | def username(self): | |
38 | """This method returns a username.""" | |
39 | return self._username | |
40 | ||
41 | @property | |
42 | def password(self): | |
43 | """This method returns a password.""" | |
44 | return self._password | |
45 | ||
46 | def __eq__(self, other): | |
47 | if isinstance(other, Password): | |
48 | return (self._username == other._username and | |
49 | self._password == other._password) | |
50 | else: | |
51 | return False | |
52 | ||
53 | def __ne__(self, other): | |
54 | result = self.__eq__(other) | |
55 | return not result |
0 | # Copyright (c) 2015 IBM | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | """ | |
15 | Base Token Credential | |
16 | ||
17 | This module defines the Token credential. | |
18 | """ | |
19 | ||
20 | from castellan.common.credentials import credential | |
21 | ||
22 | ||
23 | class Token(credential.Credential): | |
24 | """This class represents a token credential.""" | |
25 | ||
26 | def __init__(self, token): | |
27 | """Create a new Token credential. | |
28 | ||
29 | :param string token: Token for authentication. | |
30 | """ | |
31 | ||
32 | self._token = token | |
33 | ||
34 | @property | |
35 | def token(self): | |
36 | """This method returns a token.""" | |
37 | return self._token | |
38 | ||
39 | def __eq__(self, other): | |
40 | if isinstance(other, Token): | |
41 | return (self._token == other._token) | |
42 | else: | |
43 | return False | |
44 | ||
45 | def __ne__(self, other): | |
46 | result = self.__eq__(other) | |
47 | return not result |
61 | 61 | |
62 | 62 | class ManagedObjectNotFoundError(CastellanException): |
63 | 63 | message = u._("Key not found, uuid: %(uuid)s") |
64 | ||
65 | ||
66 | class AuthTypeInvalidError(CastellanException): | |
67 | message = u._("Invalid auth_type was specified, auth_type: %(type)s") | |
68 | ||
69 | ||
70 | class InsufficientCredentialDataError(CastellanException): | |
71 | message = u._("Insufficient credential data was provided, either " | |
72 | "\"token\" must be set in the passed conf, or a context " | |
73 | "with an \"auth_token\" property must be passed.") |
18 | 18 | This module defines the ManagedObject class. The ManagedObject class |
19 | 19 | is the base class to represent all objects managed by the key manager. |
20 | 20 | """ |
21 | ||
22 | 21 | import abc |
23 | 22 | |
24 | 23 | import six |
28 | 27 | class ManagedObject(object): |
29 | 28 | """Base class to represent all managed objects.""" |
30 | 29 | |
31 | def __init__(self, name=None): | |
32 | """Managed Object has a name, defaulted to None.""" | |
30 | def __init__(self, name=None, created=None): | |
31 | """Managed Object | |
32 | ||
33 | :param name: the name of the managed object. | |
34 | :param created: the time a managed object was created. | |
35 | """ | |
33 | 36 | self._name = name |
37 | ||
38 | # If None or POSIX times | |
39 | if not created or type(created) == int: | |
40 | self._created = created | |
41 | else: | |
42 | raise ValueError('created must be of long type, actual type %s' % | |
43 | type(created)) | |
34 | 44 | |
35 | 45 | @property |
36 | 46 | def name(self): |
39 | 49 | Returns the object's name or None if this object does not have one. |
40 | 50 | """ |
41 | 51 | return self._name |
52 | ||
53 | @property | |
54 | def created(self): | |
55 | """Returns the POSIX time(long) of the object that was created. | |
56 | ||
57 | Returns the POSIX time(long) of the object that was created or None if | |
58 | the object does not have one, meaning it has not been persisted. | |
59 | """ | |
60 | return self._created | |
42 | 61 | |
43 | 62 | @abc.abstractproperty |
44 | 63 | def format(self): |
24 | 24 | class OpaqueData(managed_object.ManagedObject): |
25 | 25 | """This class represents opaque data.""" |
26 | 26 | |
27 | def __init__(self, data, name=None): | |
27 | def __init__(self, data, name=None, created=None): | |
28 | 28 | """Create a new OpaqueData object. |
29 | 29 | |
30 | 30 | Expected type for data is a bytestring. |
31 | 31 | """ |
32 | 32 | self._data = data |
33 | super(OpaqueData, self).__init__(name=name) | |
33 | super(OpaqueData, self).__init__(name=name, created=created) | |
34 | 34 | |
35 | 35 | @property |
36 | 36 | def format(self): |
43 | 43 | |
44 | 44 | def __eq__(self, other): |
45 | 45 | if isinstance(other, OpaqueData): |
46 | return (self._data == other._data and | |
47 | self._name == other._name) | |
46 | return (self._data == other._data) | |
48 | 47 | else: |
49 | 48 | return False |
50 | 49 |
24 | 24 | class Passphrase(managed_object.ManagedObject): |
25 | 25 | """This class represents a passphrase.""" |
26 | 26 | |
27 | def __init__(self, passphrase, name=None): | |
27 | def __init__(self, passphrase, name=None, created=None): | |
28 | 28 | """Create a new Passphrase object. |
29 | 29 | |
30 | 30 | The expected type for the passphrase is a bytestring. |
31 | 31 | """ |
32 | 32 | self._passphrase = passphrase |
33 | super(Passphrase, self).__init__(name=name) | |
33 | super(Passphrase, self).__init__(name=name, created=created) | |
34 | 34 | |
35 | 35 | @property |
36 | 36 | def format(self): |
43 | 43 | |
44 | 44 | def __eq__(self, other): |
45 | 45 | if isinstance(other, Passphrase): |
46 | return (self._passphrase == other._passphrase and | |
47 | self._name == other._name) | |
46 | return (self._passphrase == other._passphrase) | |
48 | 47 | else: |
49 | 48 | return False |
50 | 49 |
24 | 24 | class PrivateKey(key.Key): |
25 | 25 | """This class represents private keys.""" |
26 | 26 | |
27 | def __init__(self, algorithm, bit_length, key, name=None): | |
27 | def __init__(self, algorithm, bit_length, key, | |
28 | name=None, created=None): | |
28 | 29 | """Create a new PrivateKey object. |
29 | 30 | |
30 | 31 | The arguments specify the algorithm and bit length for the asymmetric |
33 | 34 | self._alg = algorithm |
34 | 35 | self._bit_length = bit_length |
35 | 36 | self._key = key |
36 | super(PrivateKey, self).__init__(name=name) | |
37 | super(PrivateKey, self).__init__(name=name, created=created) | |
37 | 38 | |
38 | 39 | @property |
39 | 40 | def algorithm(self): |
58 | 59 | if isinstance(other, PrivateKey): |
59 | 60 | return (self._alg == other._alg and |
60 | 61 | self._bit_length == other._bit_length and |
61 | self._key == other._key and | |
62 | self._name == other._name) | |
62 | self._key == other._key) | |
63 | 63 | else: |
64 | 64 | return False |
65 | 65 |
24 | 24 | class PublicKey(key.Key): |
25 | 25 | """This class represents public keys.""" |
26 | 26 | |
27 | def __init__(self, algorithm, bit_length, key, name=None): | |
27 | def __init__(self, algorithm, bit_length, key, | |
28 | name=None, created=None): | |
28 | 29 | """Create a new PublicKey object. |
29 | 30 | |
30 | 31 | The arguments specify the algorithm and bit length for the asymmetric |
34 | 35 | self._alg = algorithm |
35 | 36 | self._bit_length = bit_length |
36 | 37 | self._key = key |
37 | super(PublicKey, self).__init__(name=name) | |
38 | super(PublicKey, self).__init__(name=name, created=created) | |
38 | 39 | |
39 | 40 | @property |
40 | 41 | def algorithm(self): |
59 | 60 | if isinstance(other, PublicKey): |
60 | 61 | return (self._alg == other._alg and |
61 | 62 | self._bit_length == other._bit_length and |
62 | self._key == other._key and | |
63 | self._name == other._name) | |
63 | self._key == other._key) | |
64 | 64 | else: |
65 | 65 | return False |
66 | 66 |
24 | 24 | class SymmetricKey(key.Key): |
25 | 25 | """This class represents symmetric keys.""" |
26 | 26 | |
27 | def __init__(self, algorithm, bit_length, key, name=None): | |
27 | def __init__(self, algorithm, bit_length, key, | |
28 | name=None, created=None): | |
28 | 29 | """Create a new SymmetricKey object. |
29 | 30 | |
30 | 31 | The arguments specify the algorithm and bit length for the symmetric |
33 | 34 | self._alg = algorithm |
34 | 35 | self._bit_length = bit_length |
35 | 36 | self._key = key |
36 | super(SymmetricKey, self).__init__(name=name) | |
37 | super(SymmetricKey, self).__init__(name=name, created=created) | |
37 | 38 | |
38 | 39 | @property |
39 | 40 | def algorithm(self): |
58 | 59 | if isinstance(other, SymmetricKey): |
59 | 60 | return (self._alg == other._alg and |
60 | 61 | self._bit_length == other._bit_length and |
61 | self._key == other._key and | |
62 | self._name == other._name) | |
62 | self._key == other._key) | |
63 | 63 | else: |
64 | 64 | return False |
65 | 65 |
24 | 24 | class X509(certificate.Certificate): |
25 | 25 | """This class represents X.509 certificates.""" |
26 | 26 | |
27 | def __init__(self, data, name=None): | |
27 | def __init__(self, data, name=None, created=None): | |
28 | 28 | """Create a new X509 object. |
29 | 29 | |
30 | 30 | The data should be in a bytestring. |
31 | 31 | """ |
32 | 32 | self._data = data |
33 | super(X509, self).__init__(name=name) | |
33 | super(X509, self).__init__(name=name, created=created) | |
34 | 34 | |
35 | 35 | @property |
36 | 36 | def format(self): |
43 | 43 | |
44 | 44 | def __eq__(self, other): |
45 | 45 | if isinstance(other, X509): |
46 | return (self._data == other._data and | |
47 | self._name == other._name) | |
46 | return (self._data == other._data) | |
48 | 47 | else: |
49 | 48 | return False |
50 | 49 |
0 | # Copyright (c) 2016 IBM | |
1 | # Licensed under the Apache License, Version 2.0 (the "License"); | |
2 | # you may not use this file except in compliance with the License. | |
3 | # You may obtain a copy of the License at | |
4 | # | |
5 | # http://www.apache.org/licenses/LICENSE-2.0 | |
6 | # | |
7 | # Unless required by applicable law or agreed to in writing, software | |
8 | # distributed under the License is distributed on an "AS IS" BASIS, | |
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
10 | # implied. | |
11 | # See the License for the specific language governing permissions and | |
12 | # limitations under the License. | |
13 | ||
14 | """ | |
15 | Common utilities for Castellan. | |
16 | """ | |
17 | ||
18 | from castellan.common.credentials import keystone_password | |
19 | from castellan.common.credentials import keystone_token | |
20 | from castellan.common.credentials import password | |
21 | from castellan.common.credentials import token | |
22 | from castellan.common import exception | |
23 | ||
24 | from oslo_config import cfg | |
25 | from oslo_log import log as logging | |
26 | ||
27 | ||
28 | LOG = logging.getLogger(__name__) | |
29 | ||
30 | credential_opts = [ | |
31 | # auth_type opt | |
32 | cfg.StrOpt('auth_type', default=None, | |
33 | help="The type of authentication credential to create. " | |
34 | "Possible values are 'token', 'password', 'keystone_token', " | |
35 | "and 'keystone_password'. Required if no context is passed to " | |
36 | "the credential factory."), | |
37 | ||
38 | # token opt | |
39 | cfg.StrOpt('token', default=None, | |
40 | help="Token for authentication. Required for 'token' and " | |
41 | "'keystone_token' auth_type if no context is passed to the " | |
42 | "credential factory."), | |
43 | ||
44 | # password opts | |
45 | cfg.StrOpt('username', default=None, | |
46 | help="Username for authentication. Required for 'password' " | |
47 | "auth_type. Optional for the 'keystone_password' auth_type."), | |
48 | cfg.StrOpt('password', default=None, | |
49 | help="Password for authentication. Required for 'password' and " | |
50 | "'keystone_password' auth_type."), | |
51 | ||
52 | # keystone credential opts | |
53 | cfg.StrOpt('user_id', default=None, | |
54 | help="User ID for authentication. Optional for " | |
55 | "'keystone_token' and 'keystone_password' auth_type."), | |
56 | cfg.StrOpt('user_domain_id', default=None, | |
57 | help="User's domain ID for authentication. Optional for " | |
58 | "'keystone_token' and 'keystone_password' auth_type."), | |
59 | cfg.StrOpt('user_domain_name', default=None, | |
60 | help="User's domain name for authentication. Optional for " | |
61 | "'keystone_token' and 'keystone_password' auth_type."), | |
62 | cfg.StrOpt('trust_id', default=None, | |
63 | help="Trust ID for trust scoping. Optional for " | |
64 | "'keystone_token' and 'keystone_password' auth_type."), | |
65 | cfg.StrOpt('domain_id', default=None, | |
66 | help="Domain ID for domain scoping. Optional for " | |
67 | "'keystone_token' and 'keystone_password' auth_type."), | |
68 | cfg.StrOpt('domain_name', default=None, | |
69 | help="Domain name for domain scoping. Optional for " | |
70 | "'keystone_token' and 'keystone_password' auth_type."), | |
71 | cfg.StrOpt('project_id', default=None, | |
72 | help="Project ID for project scoping. Optional for " | |
73 | "'keystone_token' and 'keystone_password' auth_type."), | |
74 | cfg.StrOpt('project_name', default=None, | |
75 | help="Project name for project scoping. Optional for " | |
76 | "'keystone_token' and 'keystone_password' auth_type."), | |
77 | cfg.StrOpt('project_domain_id', default=None, | |
78 | help="Project's domain ID for project. Optional for " | |
79 | "'keystone_token' and 'keystone_password' auth_type."), | |
80 | cfg.StrOpt('project_domain_name', default=None, | |
81 | help="Project's domain name for project. Optional for " | |
82 | "'keystone_token' and 'keystone_password' auth_type."), | |
83 | cfg.BoolOpt('reauthenticate', default=True, | |
84 | help="Allow fetching a new token if the current one is " | |
85 | "going to expire. Optional for 'keystone_token' and " | |
86 | "'keystone_password' auth_type.") | |
87 | ] | |
88 | ||
89 | OPT_GROUP = 'key_manager' | |
90 | ||
91 | ||
92 | def credential_factory(conf=None, context=None): | |
93 | """This function provides a factory for credentials. | |
94 | ||
95 | It is used to create an appropriare credential object | |
96 | from a passed configuration. This should be called before | |
97 | making any calls to a key manager. | |
98 | ||
99 | :param conf: Configuration file which this factory method uses | |
100 | to generate a credential object. Note: In the future it will | |
101 | become a required field. | |
102 | :param context: Context used for authentication. It can be used | |
103 | in conjunction with the configuration file. If no conf is passed, | |
104 | then the context object will be converted to a KeystoneToken and | |
105 | returned. If a conf is passed then only the 'token' is grabbed from | |
106 | the context for the authentication types that require a token. | |
107 | :returns: A credential object used for authenticating with the | |
108 | Castellan key manager. Type of credential returned depends on | |
109 | config and/or context passed. | |
110 | """ | |
111 | if conf: | |
112 | conf.register_opts(credential_opts, group=OPT_GROUP) | |
113 | ||
114 | if conf.key_manager.auth_type == 'token': | |
115 | if conf.key_manager.token: | |
116 | auth_token = conf.key_manager.token | |
117 | elif context: | |
118 | auth_token = context.auth_token | |
119 | else: | |
120 | raise exception.InsufficientCredentialDataError() | |
121 | ||
122 | return token.Token(auth_token) | |
123 | ||
124 | elif conf.key_manager.auth_type == 'password': | |
125 | return password.Password( | |
126 | conf.key_manager.username, | |
127 | conf.key_manager.password) | |
128 | ||
129 | elif conf.key_manager.auth_type == 'keystone_password': | |
130 | return keystone_password.KeystonePassword( | |
131 | conf.key_manager.password, | |
132 | username=conf.key_manager.username, | |
133 | user_id=conf.key_manager.user_id, | |
134 | user_domain_id=conf.key_manager.user_domain_id, | |
135 | user_domain_name=conf.key_manager.user_domain_name, | |
136 | trust_id=conf.key_manager.trust_id, | |
137 | domain_id=conf.key_manager.domain_id, | |
138 | domain_name=conf.key_manager.domain_name, | |
139 | project_id=conf.key_manager.project_id, | |
140 | project_name=conf.key_manager.project_name, | |
141 | project_domain_id=conf.key_manager.domain_id, | |
142 | project_domain_name=conf.key_manager.domain_name, | |
143 | reauthenticate=conf.key_manager.reauthenticate) | |
144 | ||
145 | elif conf.key_manager.auth_type == 'keystone_token': | |
146 | if conf.key_manager.token: | |
147 | auth_token = conf.key_manager.token | |
148 | elif context: | |
149 | auth_token = context.auth_token | |
150 | else: | |
151 | raise exception.InsufficientCredentialDataError() | |
152 | ||
153 | return keystone_token.KeystoneToken( | |
154 | auth_token, | |
155 | trust_id=conf.key_manager.trust_id, | |
156 | domain_id=conf.key_manager.domain_id, | |
157 | domain_name=conf.key_manager.domain_name, | |
158 | project_id=conf.key_manager.project_id, | |
159 | project_name=conf.key_manager.project_name, | |
160 | project_domain_id=conf.key_manager.domain_id, | |
161 | project_domain_name=conf.key_manager.domain_name, | |
162 | reauthenticate=conf.key_manager.reauthenticate) | |
163 | ||
164 | else: | |
165 | LOG.error("Invalid auth_type specified.") | |
166 | raise exception.AuthTypeInvalidError( | |
167 | type=conf.key_manager.auth_type) | |
168 | ||
169 | # for compatibility between _TokenData and RequestContext | |
170 | if hasattr(context, 'tenant') and context.tenant: | |
171 | project_id = context.tenant | |
172 | elif hasattr(context, 'project_id') and context.project_id: | |
173 | project_id = context.project_id | |
174 | ||
175 | return keystone_token.KeystoneToken( | |
176 | context.auth_token, | |
177 | project_id=project_id) |
27 | 27 | conf.register_opts(key_manager_opts, group='key_manager') |
28 | 28 | |
29 | 29 | cls = importutils.import_class(conf.key_manager.api_class) |
30 | return cls(configuration=conf)⏎ | |
30 | return cls(configuration=conf) |
15 | 15 | """ |
16 | 16 | Key manager implementation for Barbican |
17 | 17 | """ |
18 | import calendar | |
18 | 19 | import time |
19 | 20 | |
20 | 21 | from cryptography.hazmat import backends |
39 | 40 | |
40 | 41 | from barbicanclient import client as barbican_client |
41 | 42 | from barbicanclient import exceptions as barbican_exceptions |
43 | from oslo_utils import timeutils | |
42 | 44 | from six.moves import urllib |
45 | ||
43 | 46 | |
44 | 47 | barbican_opts = [ |
45 | 48 | cfg.StrOpt('barbican_endpoint', |
99 | 102 | LOG.error(msg) |
100 | 103 | raise exception.Forbidden(msg) |
101 | 104 | |
102 | if not hasattr(context, 'tenant') or context.tenant is None: | |
103 | msg = u._("Unable to create Barbican Client without tenant " | |
104 | "attribute in context object.") | |
105 | LOG.error(msg) | |
106 | raise exception.KeyManagerError(reason=msg) | |
107 | ||
108 | 105 | if self._barbican_client and self._current_context == context: |
109 | 106 | return self._barbican_client |
110 | 107 | |
111 | 108 | try: |
112 | self._current_context = context | |
113 | 109 | auth = self._get_keystone_auth(context) |
114 | 110 | sess = session.Session(auth=auth) |
115 | 111 | |
117 | 113 | self._barbican_client = barbican_client.Client( |
118 | 114 | session=sess, |
119 | 115 | endpoint=self._barbican_endpoint) |
116 | self._current_context = context | |
120 | 117 | |
121 | 118 | except Exception as e: |
122 | 119 | LOG.error(u._LE("Error creating Barbican client: %s"), e) |
129 | 126 | return self._barbican_client |
130 | 127 | |
131 | 128 | def _get_keystone_auth(self, context): |
132 | # TODO(kfarr): support keystone v2 | |
133 | auth = identity.v3.Token( | |
134 | auth_url=self.conf.barbican.auth_endpoint, | |
135 | token=context.auth_token, | |
136 | project_id=context.tenant, | |
137 | domain_id=context.user_domain, | |
138 | project_domain_id=context.project_domain) | |
139 | return auth | |
129 | auth_url = self.conf.barbican.auth_endpoint | |
130 | ||
131 | if context.__class__.__name__ is 'KeystonePassword': | |
132 | return identity.v3.Password( | |
133 | auth_url=auth_url, | |
134 | username=context.username, | |
135 | password=context.password, | |
136 | user_id=context.user_id, | |
137 | user_domain_id=context.user_domain_id, | |
138 | user_domain_name=context.user_domain_name, | |
139 | trust_id=context.trust_id, | |
140 | domain_id=context.domain_id, | |
141 | domain_name=context.domain_name, | |
142 | project_id=context.project_id, | |
143 | project_name=context.project_name, | |
144 | project_domain_id=context.project_domain_id, | |
145 | project_domain_name=context.project_domain_name, | |
146 | reauthenticate=context.reauthenticate) | |
147 | elif context.__class__.__name__ is 'KeystoneToken': | |
148 | return identity.v3.Token( | |
149 | auth_url=auth_url, | |
150 | token=context.token, | |
151 | trust_id=context.trust_id, | |
152 | domain_id=context.domain_id, | |
153 | domain_name=context.domain_name, | |
154 | project_id=context.project_id, | |
155 | project_name=context.project_name, | |
156 | project_domain_id=context.project_domain_id, | |
157 | project_domain_name=context.project_domain_name, | |
158 | reauthenticate=context.reauthenticate) | |
159 | # this will be kept for oslo.context compatibility until | |
160 | # projects begin to use utils.credential_factory | |
161 | elif context.__class__.__name__ is 'RequestContext': | |
162 | return identity.v3.Token( | |
163 | auth_url=auth_url, | |
164 | token=context.auth_token, | |
165 | project_id=context.tenant) | |
166 | else: | |
167 | msg = "context must be of type KeystonePassword, KeystoneToken, " | |
168 | "or RequestContext." | |
169 | LOG.error(msg) | |
170 | raise exception.Forbidden(reason=msg) | |
140 | 171 | |
141 | 172 | def _get_barbican_endpoint(self, auth, sess): |
142 | 173 | if self.conf.barbican.barbican_endpoint: |
332 | 363 | Barbican key creation is done asynchronously, so this loop continues |
333 | 364 | checking until the order is active or a timeout occurs. |
334 | 365 | """ |
335 | active = u'ACTIVE' | |
366 | active_status = u'ACTIVE' | |
367 | error_status = u'ERROR' | |
336 | 368 | number_of_retries = self.conf.barbican.number_of_retries |
337 | 369 | retry_delay = self.conf.barbican.retry_delay |
338 | 370 | order = barbican_client.orders.get(order_ref) |
339 | 371 | time.sleep(.25) |
340 | 372 | for n in range(number_of_retries): |
341 | if order.status != active: | |
373 | if order.status == error_status: | |
374 | kwargs = {"status": error_status, | |
375 | "code": order.error_status_code, | |
376 | "reason": order.error_reason} | |
377 | msg = u._LE("Order is in %(status)s status - status code: " | |
378 | "%(code)s, status reason: %(reason)s") % kwargs | |
379 | LOG.error(msg) | |
380 | raise exception.KeyManagerError(reason=msg) | |
381 | if order.status != active_status: | |
342 | 382 | kwargs = {'attempt': n, |
343 | 383 | 'total': number_of_retries, |
344 | 384 | 'status': order.status, |
345 | 'active': active, | |
385 | 'active': active_status, | |
346 | 386 | 'delay': retry_delay} |
347 | 387 | msg = u._LI("Retry attempt #%(attempt)i out of %(total)i: " |
348 | 388 | "Order status is '%(status)s'. Waiting for " |
354 | 394 | else: |
355 | 395 | return order |
356 | 396 | msg = u._LE("Exceeded retries: Failed to find '%(active)s' status " |
357 | "within %(num_retries)i retries") % {'active': active, | |
358 | 'num_retries': | |
359 | number_of_retries} | |
397 | "within %(num_retries)i retries") % { | |
398 | 'active': active_status, | |
399 | 'num_retries': number_of_retries} | |
360 | 400 | LOG.error(msg) |
361 | 401 | raise exception.KeyManagerError(reason=msg) |
362 | 402 | |
420 | 460 | |
421 | 461 | secret_data = self._get_secret_data(secret) |
422 | 462 | |
463 | # convert created ISO8601 in Barbican to POSIX | |
464 | if secret.created: | |
465 | time_stamp = timeutils.parse_isotime( | |
466 | str(secret.created)).timetuple() | |
467 | created = calendar.timegm(time_stamp) | |
468 | ||
423 | 469 | if issubclass(secret_type, key_base_class.Key): |
424 | 470 | return secret_type(secret.algorithm, |
425 | 471 | secret.bit_length, |
426 | 472 | secret_data, |
427 | secret.name) | |
473 | secret.name, | |
474 | created) | |
428 | 475 | else: |
429 | 476 | return secret_type(secret_data, |
430 | secret.name) | |
477 | secret.name, | |
478 | created) | |
431 | 479 | |
432 | 480 | def _get_secret(self, context, object_id): |
433 | 481 | """Returns the metadata of the secret. |
19 | 19 | from castellan.key_manager import barbican_key_manager as bkm |
20 | 20 | except ImportError: |
21 | 21 | bkm = None |
22 | from castellan.common import utils | |
22 | 23 | |
23 | 24 | _DEFAULT_LOG_LEVELS = ['castellan=WARN'] |
24 | 25 | |
93 | 94 | |
94 | 95 | :returns: a list of (group_name, opts) tuples |
95 | 96 | """ |
96 | opts = [('key_manager', km.key_manager_opts)] | |
97 | key_manager_opts = [] | |
98 | key_manager_opts.extend(km.key_manager_opts) | |
99 | key_manager_opts.extend(utils.credential_opts) | |
100 | opts = [('key_manager', key_manager_opts)] | |
101 | ||
97 | 102 | if bkm is not None: |
98 | 103 | opts.append((bkm.BARBICAN_OPT_GROUP, bkm.barbican_opts)) |
99 | 104 | return opts |
20 | 20 | |
21 | 21 | identity_group = cfg.OptGroup(name='identity') |
22 | 22 | identity_options = [ |
23 | cfg.StrOpt('uri', | |
23 | cfg.StrOpt('auth_url', | |
24 | 24 | default='http://localhost:5000/v3', |
25 | 25 | help='Keystone endpoint'), |
26 | 26 | cfg.StrOpt('username', |
31 | 31 | help='Password used with Keystone username'), |
32 | 32 | cfg.StrOpt('project_name', |
33 | 33 | default='admin', |
34 | help='Name of project, used by the given username')] | |
34 | help='Name of project, used by the given username'), | |
35 | cfg.StrOpt('user_domain_name', | |
36 | default='Default', | |
37 | help='Name of domain, used by the given username'), | |
38 | cfg.StrOpt('project_domain_name', | |
39 | default='Default', | |
40 | help='Name of domain, used by the given project')] | |
35 | 41 | |
36 | 42 | |
37 | 43 | def setup_config(config_file=''): |
43 | 49 | |
44 | 50 | config_to_load = [] |
45 | 51 | local_config = './../../../etc/castellan/castellan-functional.conf' |
52 | main_config = '/etc/castellan/castellan-functional.conf' | |
46 | 53 | if os.path.isfile(config_file): |
47 | 54 | config_to_load.append(config_file) |
48 | 55 | elif os.path.isfile(local_config): |
49 | 56 | config_to_load.append(local_config) |
50 | else: | |
51 | config_to_load.append('/etc/castellan/castellan-functional.conf') | |
57 | elif os.path.isfile(main_config): | |
58 | config_to_load.append(main_config) | |
52 | 59 | |
53 | 60 | TEST_CONF( |
54 | 61 | (), # Required to load an anonymous config |
20 | 20 | |
21 | 21 | import uuid |
22 | 22 | |
23 | from keystoneclient.auth.identity import v3 | |
24 | from keystoneclient import session | |
23 | 25 | from keystoneclient.v3 import client |
24 | 26 | from oslo_config import cfg |
25 | 27 | from oslo_context import context |
26 | 28 | from oslotest import base |
27 | 29 | |
30 | from castellan.common.credentials import keystone_password | |
31 | from castellan.common.credentials import keystone_token | |
28 | 32 | from castellan.common import exception |
29 | 33 | from castellan.key_manager import barbican_key_manager |
30 | 34 | from castellan.tests.functional import config |
45 | 49 | username = CONF.identity.username |
46 | 50 | password = CONF.identity.password |
47 | 51 | project_name = CONF.identity.project_name |
48 | auth_url = CONF.identity.uri | |
49 | keystone_client = client.Client(username=username, | |
50 | password=password, | |
51 | project_name=project_name, | |
52 | auth_url=auth_url, | |
53 | project_domain_id='default') | |
52 | auth_url = CONF.identity.auth_url | |
53 | user_domain_name = CONF.identity.user_domain_name | |
54 | project_domain_name = CONF.identity.project_domain_name | |
55 | ||
56 | auth = v3.Password(auth_url=auth_url, | |
57 | username=username, | |
58 | password=password, | |
59 | project_name=project_name, | |
60 | user_domain_name=user_domain_name, | |
61 | project_domain_name=project_domain_name) | |
62 | sess = session.Session(auth=auth) | |
63 | keystone_client = client.Client(session=sess) | |
64 | ||
54 | 65 | project_list = keystone_client.projects.list(name=project_name) |
55 | 66 | |
56 | 67 | self.ctxt = context.RequestContext( |
57 | auth_token=keystone_client.auth_token, | |
68 | auth_token=auth.auth_ref.auth_token, | |
58 | 69 | tenant=project_list[0].id) |
59 | 70 | |
60 | 71 | def tearDown(self): |
104 | 115 | |
105 | 116 | self.assertRaises(exception.Forbidden, |
106 | 117 | self.key_mgr.store, None, key) |
118 | ||
119 | ||
120 | class BarbicanKeyManagerKSPasswordTestCase(test_key_manager.KeyManagerTestCase, | |
121 | base.BaseTestCase): | |
122 | ||
123 | def _create_key_manager(self): | |
124 | return barbican_key_manager.BarbicanKeyManager(cfg.CONF) | |
125 | ||
126 | def setUp(self): | |
127 | super(BarbicanKeyManagerKSPasswordTestCase, self).setUp() | |
128 | username = CONF.identity.username | |
129 | password = CONF.identity.password | |
130 | project_name = CONF.identity.project_name | |
131 | user_domain_name = CONF.identity.user_domain_name | |
132 | project_domain_name = CONF.identity.project_domain_name | |
133 | ||
134 | self.ctxt = keystone_password.KeystonePassword( | |
135 | username=username, | |
136 | password=password, | |
137 | project_name=project_name, | |
138 | user_domain_name=user_domain_name, | |
139 | project_domain_name=project_domain_name) | |
140 | ||
141 | def tearDown(self): | |
142 | super(BarbicanKeyManagerKSPasswordTestCase, self).tearDown() | |
143 | ||
144 | def test_create_null_context(self): | |
145 | self.assertRaises(exception.Forbidden, | |
146 | self.key_mgr.create_key, None, 'AES', 256) | |
147 | ||
148 | def test_create_key_pair_null_context(self): | |
149 | self.assertRaises(exception.Forbidden, | |
150 | self.key_mgr.create_key_pair, None, 'RSA', 2048) | |
151 | ||
152 | def test_delete_null_context(self): | |
153 | key_uuid = self._get_valid_object_uuid( | |
154 | test_key_manager._get_test_symmetric_key()) | |
155 | self.addCleanup(self.key_mgr.delete, self.ctxt, key_uuid) | |
156 | self.assertRaises(exception.Forbidden, | |
157 | self.key_mgr.delete, None, key_uuid) | |
158 | ||
159 | def test_delete_null_object(self): | |
160 | self.assertRaises(exception.KeyManagerError, | |
161 | self.key_mgr.delete, self.ctxt, None) | |
162 | ||
163 | def test_delete_unknown_object(self): | |
164 | unknown_uuid = str(uuid.uuid4()) | |
165 | self.assertRaises(exception.ManagedObjectNotFoundError, | |
166 | self.key_mgr.delete, self.ctxt, unknown_uuid) | |
167 | ||
168 | def test_get_null_context(self): | |
169 | key_uuid = self._get_valid_object_uuid( | |
170 | test_key_manager._get_test_symmetric_key()) | |
171 | self.assertRaises(exception.Forbidden, | |
172 | self.key_mgr.get, None, key_uuid) | |
173 | ||
174 | def test_get_null_object(self): | |
175 | self.assertRaises(exception.KeyManagerError, | |
176 | self.key_mgr.get, self.ctxt, None) | |
177 | ||
178 | def test_get_unknown_key(self): | |
179 | bad_key_uuid = str(uuid.uuid4()) | |
180 | self.assertRaises(exception.ManagedObjectNotFoundError, | |
181 | self.key_mgr.get, self.ctxt, bad_key_uuid) | |
182 | ||
183 | def test_store_null_context(self): | |
184 | key = test_key_manager._get_test_symmetric_key() | |
185 | ||
186 | self.assertRaises(exception.Forbidden, | |
187 | self.key_mgr.store, None, key) | |
188 | ||
189 | ||
190 | class BarbicanKeyManagerKSTokenTestCase(test_key_manager.KeyManagerTestCase, | |
191 | base.BaseTestCase): | |
192 | ||
193 | def _create_key_manager(self): | |
194 | return barbican_key_manager.BarbicanKeyManager(cfg.CONF) | |
195 | ||
196 | def setUp(self): | |
197 | super(BarbicanKeyManagerKSTokenTestCase, self).setUp() | |
198 | username = CONF.identity.username | |
199 | password = CONF.identity.password | |
200 | project_name = CONF.identity.project_name | |
201 | auth_url = CONF.identity.auth_url | |
202 | user_domain_name = CONF.identity.user_domain_name | |
203 | project_domain_name = CONF.identity.project_domain_name | |
204 | ||
205 | auth = v3.Password(auth_url=auth_url, | |
206 | username=username, | |
207 | password=password, | |
208 | project_name=project_name, | |
209 | user_domain_name=user_domain_name, | |
210 | project_domain_name=project_domain_name) | |
211 | sess = session.Session(auth=auth) | |
212 | keystone_client = client.Client(session=sess) | |
213 | ||
214 | project_list = keystone_client.projects.list(name=project_name) | |
215 | ||
216 | self.ctxt = keystone_token.KeystoneToken( | |
217 | token=auth.auth_ref.auth_token, | |
218 | project_id=project_list[0].id) | |
219 | ||
220 | def tearDown(self): | |
221 | super(BarbicanKeyManagerKSTokenTestCase, self).tearDown() | |
222 | ||
223 | def test_create_null_context(self): | |
224 | self.assertRaises(exception.Forbidden, | |
225 | self.key_mgr.create_key, None, 'AES', 256) | |
226 | ||
227 | def test_create_key_pair_null_context(self): | |
228 | self.assertRaises(exception.Forbidden, | |
229 | self.key_mgr.create_key_pair, None, 'RSA', 2048) | |
230 | ||
231 | def test_delete_null_context(self): | |
232 | key_uuid = self._get_valid_object_uuid( | |
233 | test_key_manager._get_test_symmetric_key()) | |
234 | self.addCleanup(self.key_mgr.delete, self.ctxt, key_uuid) | |
235 | self.assertRaises(exception.Forbidden, | |
236 | self.key_mgr.delete, None, key_uuid) | |
237 | ||
238 | def test_delete_null_object(self): | |
239 | self.assertRaises(exception.KeyManagerError, | |
240 | self.key_mgr.delete, self.ctxt, None) | |
241 | ||
242 | def test_delete_unknown_object(self): | |
243 | unknown_uuid = str(uuid.uuid4()) | |
244 | self.assertRaises(exception.ManagedObjectNotFoundError, | |
245 | self.key_mgr.delete, self.ctxt, unknown_uuid) | |
246 | ||
247 | def test_get_null_context(self): | |
248 | key_uuid = self._get_valid_object_uuid( | |
249 | test_key_manager._get_test_symmetric_key()) | |
250 | self.assertRaises(exception.Forbidden, | |
251 | self.key_mgr.get, None, key_uuid) | |
252 | ||
253 | def test_get_null_object(self): | |
254 | self.assertRaises(exception.KeyManagerError, | |
255 | self.key_mgr.get, self.ctxt, None) | |
256 | ||
257 | def test_get_unknown_key(self): | |
258 | bad_key_uuid = str(uuid.uuid4()) | |
259 | self.assertRaises(exception.ManagedObjectNotFoundError, | |
260 | self.key_mgr.get, self.ctxt, bad_key_uuid) | |
261 | ||
262 | def test_store_null_context(self): | |
263 | key = test_key_manager._get_test_symmetric_key() | |
264 | ||
265 | self.assertRaises(exception.Forbidden, | |
266 | self.key_mgr.store, None, key) |
0 | # Copyright (c) 2015 IBM | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | ||
15 | """ | |
16 | Test cases for the keystone password credential | |
17 | """ | |
18 | ||
19 | from castellan.common.credentials import keystone_password | |
20 | from castellan.tests import base | |
21 | ||
22 | ||
23 | class KeystonePasswordTestCase(base.TestCase): | |
24 | ||
25 | def _create_ks_password_credential(self): | |
26 | return keystone_password.KeystonePassword( | |
27 | self.password, | |
28 | username=self.username, | |
29 | user_id=self.user_id, | |
30 | user_domain_id=self.user_domain_id, | |
31 | user_domain_name=self.user_domain_name, | |
32 | trust_id=self.trust_id, | |
33 | domain_id=self.domain_id, | |
34 | domain_name=self.domain_name, | |
35 | project_id=self.project_id, | |
36 | project_name=self.project_name, | |
37 | project_domain_id=self.project_domain_id, | |
38 | project_domain_name=self.project_domain_name, | |
39 | reauthenticate=self.reauthenticate) | |
40 | ||
41 | def setUp(self): | |
42 | self.password = "Pa$$w0rd1", | |
43 | self.username = "admin", | |
44 | self.user_id = "1adb2391c009443aa5224b316d4a06ae", | |
45 | self.user_domain_id = "default", | |
46 | self.user_domain_name = "default", | |
47 | self.trust_id = "14b38a8296f144148138466ce9280940", | |
48 | self.domain_id = "default", | |
49 | self.domain_name = "default", | |
50 | self.project_id = "1099302ec608486f9879ba2466c60720", | |
51 | self.project_name = "demo", | |
52 | self.project_domain_id = "default", | |
53 | self.project_domain_name = "default", | |
54 | self.reauthenticate = True | |
55 | ||
56 | self.ks_password_credential = self._create_ks_password_credential() | |
57 | ||
58 | super(KeystonePasswordTestCase, self).setUp() | |
59 | ||
60 | def test_get_password(self): | |
61 | self.assertEqual(self.password, | |
62 | self.ks_password_credential.password) | |
63 | ||
64 | def test_get_username(self): | |
65 | self.assertEqual(self.username, | |
66 | self.ks_password_credential.username) | |
67 | ||
68 | def test_get_user_id(self): | |
69 | self.assertEqual(self.user_id, | |
70 | self.ks_password_credential.user_id) | |
71 | ||
72 | def test_get_user_domain_id(self): | |
73 | self.assertEqual(self.user_domain_id, | |
74 | self.ks_password_credential.user_domain_id) | |
75 | ||
76 | def test_get_user_domain_name(self): | |
77 | self.assertEqual(self.user_domain_name, | |
78 | self.ks_password_credential.user_domain_name) | |
79 | ||
80 | def test_get_trust_id(self): | |
81 | self.assertEqual(self.trust_id, | |
82 | self.ks_password_credential.trust_id) | |
83 | ||
84 | def test_get_domain_id(self): | |
85 | self.assertEqual(self.domain_id, | |
86 | self.ks_password_credential.domain_id) | |
87 | ||
88 | def test_get_domain_name(self): | |
89 | self.assertEqual(self.domain_name, | |
90 | self.ks_password_credential.domain_name) | |
91 | ||
92 | def test_get_project_id(self): | |
93 | self.assertEqual(self.project_id, | |
94 | self.ks_password_credential.project_id) | |
95 | ||
96 | def test_get_project_name(self): | |
97 | self.assertEqual(self.project_name, | |
98 | self.ks_password_credential.project_name) | |
99 | ||
100 | def test_get_project_domain_id(self): | |
101 | self.assertEqual(self.project_domain_id, | |
102 | self.ks_password_credential.project_domain_id) | |
103 | ||
104 | def test_get_project_domain_name(self): | |
105 | self.assertEqual(self.project_domain_name, | |
106 | self.ks_password_credential.project_domain_name) | |
107 | ||
108 | def test_get_reauthenticate(self): | |
109 | self.assertEqual(self.reauthenticate, | |
110 | self.ks_password_credential.reauthenticate) | |
111 | ||
112 | def test___eq__(self): | |
113 | self.assertTrue(self.ks_password_credential == | |
114 | self.ks_password_credential) | |
115 | self.assertTrue(self.ks_password_credential is | |
116 | self.ks_password_credential) | |
117 | ||
118 | self.assertFalse(self.ks_password_credential is None) | |
119 | self.assertFalse(None == self.ks_password_credential) | |
120 | ||
121 | other_ks_password_credential = keystone_password.KeystonePassword( | |
122 | self.password, | |
123 | username=self.username, | |
124 | user_id=self.user_id, | |
125 | user_domain_id=self.user_domain_id, | |
126 | user_domain_name=self.user_domain_name, | |
127 | trust_id=self.trust_id, | |
128 | domain_id=self.domain_id, | |
129 | domain_name=self.domain_name, | |
130 | project_id=self.project_id, | |
131 | project_name=self.project_name, | |
132 | project_domain_id=self.project_domain_id, | |
133 | project_domain_name=self.project_domain_name, | |
134 | reauthenticate=self.reauthenticate) | |
135 | self.assertTrue(self.ks_password_credential == | |
136 | other_ks_password_credential) | |
137 | self.assertFalse(self.ks_password_credential is | |
138 | other_ks_password_credential) | |
139 | ||
140 | def test___ne___none(self): | |
141 | self.assertTrue(self.ks_password_credential is not None) | |
142 | self.assertTrue(None != self.ks_password_credential) | |
143 | ||
144 | def test___ne___password(self): | |
145 | other_password = "wheresmyCat??" | |
146 | ||
147 | other_ks_password_credential = keystone_password.KeystonePassword( | |
148 | other_password, | |
149 | username=self.username, | |
150 | user_id=self.user_id, | |
151 | user_domain_id=self.user_domain_id, | |
152 | user_domain_name=self.user_domain_name, | |
153 | trust_id=self.trust_id, | |
154 | domain_id=self.domain_id, | |
155 | domain_name=self.domain_name, | |
156 | project_id=self.project_id, | |
157 | project_name=self.project_name, | |
158 | project_domain_id=self.project_domain_id, | |
159 | project_domain_name=self.project_domain_name, | |
160 | reauthenticate=self.reauthenticate) | |
161 | ||
162 | self.assertTrue(self.ks_password_credential != | |
163 | other_ks_password_credential) | |
164 | ||
165 | def test___ne___username(self): | |
166 | other_username = "service" | |
167 | ||
168 | other_ks_password_credential = keystone_password.KeystonePassword( | |
169 | self.password, | |
170 | username=other_username, | |
171 | user_id=self.user_id, | |
172 | user_domain_id=self.user_domain_id, | |
173 | user_domain_name=self.user_domain_name, | |
174 | trust_id=self.trust_id, | |
175 | domain_id=self.domain_id, | |
176 | domain_name=self.domain_name, | |
177 | project_id=self.project_id, | |
178 | project_name=self.project_name, | |
179 | project_domain_id=self.project_domain_id, | |
180 | project_domain_name=self.project_domain_name, | |
181 | reauthenticate=self.reauthenticate) | |
182 | ||
183 | self.assertTrue(self.ks_password_credential != | |
184 | other_ks_password_credential) | |
185 | ||
186 | def test___ne___user_id(self): | |
187 | other_user_id = "service" | |
188 | ||
189 | other_ks_password_credential = keystone_password.KeystonePassword( | |
190 | self.password, | |
191 | username=self.username, | |
192 | user_id=other_user_id, | |
193 | user_domain_id=self.user_domain_id, | |
194 | user_domain_name=self.user_domain_name, | |
195 | trust_id=self.trust_id, | |
196 | domain_id=self.domain_id, | |
197 | domain_name=self.domain_name, | |
198 | project_id=self.project_id, | |
199 | project_name=self.project_name, | |
200 | project_domain_id=self.project_domain_id, | |
201 | project_domain_name=self.project_domain_name, | |
202 | reauthenticate=self.reauthenticate) | |
203 | ||
204 | self.assertTrue(self.ks_password_credential != | |
205 | other_ks_password_credential) | |
206 | ||
207 | def test___ne___user_domain_id(self): | |
208 | other_user_domain_id = "domain0" | |
209 | ||
210 | other_ks_password_credential = keystone_password.KeystonePassword( | |
211 | self.password, | |
212 | username=self.username, | |
213 | user_id=self.user_id, | |
214 | user_domain_id=other_user_domain_id, | |
215 | user_domain_name=self.user_domain_name, | |
216 | trust_id=self.trust_id, | |
217 | domain_id=self.domain_id, | |
218 | domain_name=self.domain_name, | |
219 | project_id=self.project_id, | |
220 | project_name=self.project_name, | |
221 | project_domain_id=self.project_domain_id, | |
222 | project_domain_name=self.project_domain_name, | |
223 | reauthenticate=self.reauthenticate) | |
224 | ||
225 | self.assertTrue(self.ks_password_credential != | |
226 | other_ks_password_credential) | |
227 | ||
228 | def test___ne___user_domain_name(self): | |
229 | other_user_domain_name = "domain0" | |
230 | ||
231 | other_ks_password_credential = keystone_password.KeystonePassword( | |
232 | self.password, | |
233 | username=self.username, | |
234 | user_id=self.user_id, | |
235 | user_domain_id=self.domain_id, | |
236 | user_domain_name=other_user_domain_name, | |
237 | trust_id=self.trust_id, | |
238 | domain_id=self.domain_id, | |
239 | domain_name=self.domain_name, | |
240 | project_id=self.project_id, | |
241 | project_name=self.project_name, | |
242 | project_domain_id=self.project_domain_id, | |
243 | project_domain_name=self.project_domain_name, | |
244 | reauthenticate=self.reauthenticate) | |
245 | ||
246 | self.assertTrue(self.ks_password_credential != | |
247 | other_ks_password_credential) | |
248 | ||
249 | def test___ne___trust_id(self): | |
250 | other_trust_id = "00000000000000" | |
251 | ||
252 | other_ks_password_credential = keystone_password.KeystonePassword( | |
253 | self.password, | |
254 | username=self.username, | |
255 | user_id=self.user_id, | |
256 | user_domain_id=self.user_domain_id, | |
257 | user_domain_name=self.user_domain_name, | |
258 | trust_id=other_trust_id, | |
259 | domain_id=self.domain_id, | |
260 | domain_name=self.domain_name, | |
261 | project_id=self.project_id, | |
262 | project_name=self.project_name, | |
263 | project_domain_id=self.project_domain_id, | |
264 | project_domain_name=self.project_domain_name, | |
265 | reauthenticate=self.reauthenticate) | |
266 | ||
267 | self.assertTrue(self.ks_password_credential != | |
268 | other_ks_password_credential) | |
269 | ||
270 | def test___ne___domain_id(self): | |
271 | other_domain_id = "domain0" | |
272 | ||
273 | other_ks_password_credential = keystone_password.KeystonePassword( | |
274 | self.password, | |
275 | username=self.username, | |
276 | user_id=self.user_id, | |
277 | user_domain_id=self.user_domain_id, | |
278 | user_domain_name=self.user_domain_name, | |
279 | trust_id=self.trust_id, | |
280 | domain_id=other_domain_id, | |
281 | domain_name=self.domain_name, | |
282 | project_id=self.project_id, | |
283 | project_name=self.project_name, | |
284 | project_domain_id=self.project_domain_id, | |
285 | project_domain_name=self.project_domain_name, | |
286 | reauthenticate=self.reauthenticate) | |
287 | ||
288 | self.assertTrue(self.ks_password_credential != | |
289 | other_ks_password_credential) | |
290 | ||
291 | def test___ne___domain_name(self): | |
292 | other_domain_name = "domain0" | |
293 | ||
294 | other_ks_password_credential = keystone_password.KeystonePassword( | |
295 | self.password, | |
296 | username=self.username, | |
297 | user_id=self.user_id, | |
298 | user_domain_id=self.user_domain_id, | |
299 | user_domain_name=self.user_domain_name, | |
300 | trust_id=self.trust_id, | |
301 | domain_id=self.domain_id, | |
302 | domain_name=other_domain_name, | |
303 | project_id=self.project_id, | |
304 | project_name=self.project_name, | |
305 | project_domain_id=self.project_domain_id, | |
306 | project_domain_name=self.project_domain_name, | |
307 | reauthenticate=self.reauthenticate) | |
308 | ||
309 | self.assertTrue(self.ks_password_credential != | |
310 | other_ks_password_credential) | |
311 | ||
312 | def test___ne___project_id(self): | |
313 | other_project_id = "00000000000000" | |
314 | ||
315 | other_ks_password_credential = keystone_password.KeystonePassword( | |
316 | self.password, | |
317 | username=self.username, | |
318 | user_id=self.user_id, | |
319 | user_domain_id=self.user_domain_id, | |
320 | user_domain_name=self.user_domain_name, | |
321 | trust_id=self.trust_id, | |
322 | domain_id=self.domain_id, | |
323 | domain_name=self.domain_name, | |
324 | project_id=other_project_id, | |
325 | project_name=self.project_name, | |
326 | project_domain_id=self.project_domain_id, | |
327 | project_domain_name=self.project_domain_name, | |
328 | reauthenticate=self.reauthenticate) | |
329 | ||
330 | self.assertTrue(self.ks_password_credential != | |
331 | other_ks_password_credential) | |
332 | ||
333 | def test___ne___project_name(self): | |
334 | other_project_name = "proj0" | |
335 | ||
336 | other_ks_password_credential = keystone_password.KeystonePassword( | |
337 | self.password, | |
338 | username=self.username, | |
339 | user_id=self.user_id, | |
340 | user_domain_id=self.user_domain_id, | |
341 | user_domain_name=self.user_domain_name, | |
342 | trust_id=self.trust_id, | |
343 | domain_id=self.domain_id, | |
344 | domain_name=self.domain_name, | |
345 | project_id=self.project_id, | |
346 | project_name=other_project_name, | |
347 | project_domain_id=self.project_domain_id, | |
348 | project_domain_name=self.project_domain_name, | |
349 | reauthenticate=self.reauthenticate) | |
350 | ||
351 | self.assertTrue(self.ks_password_credential != | |
352 | other_ks_password_credential) | |
353 | ||
354 | def test___ne___project_domain_id(self): | |
355 | other_project_domain_id = "domain0" | |
356 | ||
357 | other_ks_password_credential = keystone_password.KeystonePassword( | |
358 | self.password, | |
359 | username=self.username, | |
360 | user_id=self.user_id, | |
361 | user_domain_id=self.user_domain_id, | |
362 | user_domain_name=self.user_domain_name, | |
363 | trust_id=self.trust_id, | |
364 | domain_id=self.domain_id, | |
365 | domain_name=self.domain_name, | |
366 | project_id=self.project_id, | |
367 | project_name=self.project_name, | |
368 | project_domain_id=other_project_domain_id, | |
369 | project_domain_name=self.project_domain_name, | |
370 | reauthenticate=self.reauthenticate) | |
371 | ||
372 | self.assertTrue(self.ks_password_credential != | |
373 | other_ks_password_credential) | |
374 | ||
375 | def test___ne___project_domain_name(self): | |
376 | other_project_domain_name = "domain0" | |
377 | ||
378 | other_ks_password_credential = keystone_password.KeystonePassword( | |
379 | self.password, | |
380 | username=self.username, | |
381 | user_id=self.user_id, | |
382 | user_domain_id=self.user_domain_id, | |
383 | user_domain_name=self.user_domain_name, | |
384 | trust_id=self.trust_id, | |
385 | domain_id=self.domain_id, | |
386 | domain_name=self.domain_name, | |
387 | project_id=self.project_id, | |
388 | project_name=self.project_name, | |
389 | project_domain_id=self.project_domain_id, | |
390 | project_domain_name=other_project_domain_name, | |
391 | reauthenticate=self.reauthenticate) | |
392 | ||
393 | self.assertTrue(self.ks_password_credential != | |
394 | other_ks_password_credential) | |
395 | ||
396 | def test___ne___reauthenticate(self): | |
397 | other_reauthenticate = False | |
398 | ||
399 | other_ks_password_credential = keystone_password.KeystonePassword( | |
400 | self.password, | |
401 | username=self.username, | |
402 | user_id=self.user_id, | |
403 | user_domain_id=self.user_domain_id, | |
404 | user_domain_name=self.user_domain_name, | |
405 | trust_id=self.trust_id, | |
406 | domain_id=self.domain_id, | |
407 | domain_name=self.domain_name, | |
408 | project_id=self.project_id, | |
409 | project_name=self.project_name, | |
410 | project_domain_id=self.project_domain_id, | |
411 | project_domain_name=self.project_domain_name, | |
412 | reauthenticate=other_reauthenticate) | |
413 | ||
414 | self.assertTrue(self.ks_password_credential != | |
415 | other_ks_password_credential) |
0 | # Copyright (c) 2015 IBM | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | ||
15 | """ | |
16 | Test cases for the keystone token credential | |
17 | """ | |
18 | ||
19 | from castellan.common.credentials import keystone_token | |
20 | from castellan.tests import base | |
21 | ||
22 | ||
23 | class KeystoneTokenTestCase(base.TestCase): | |
24 | ||
25 | def _create_ks_token_credential(self): | |
26 | return keystone_token.KeystoneToken( | |
27 | self.token, | |
28 | trust_id=self.trust_id, | |
29 | domain_id=self.domain_id, | |
30 | domain_name=self.domain_name, | |
31 | project_id=self.project_id, | |
32 | project_name=self.project_name, | |
33 | project_domain_id=self.project_domain_id, | |
34 | project_domain_name=self.project_domain_name, | |
35 | reauthenticate=self.reauthenticate) | |
36 | ||
37 | def setUp(self): | |
38 | self.token = "8a4aa147d58141c39a7a22905b90ba4e", | |
39 | self.trust_id = "14b38a8296f144148138466ce9280940", | |
40 | self.domain_id = "default", | |
41 | self.domain_name = "default", | |
42 | self.project_id = "1099302ec608486f9879ba2466c60720", | |
43 | self.project_name = "demo", | |
44 | self.project_domain_id = "default", | |
45 | self.project_domain_name = "default", | |
46 | self.reauthenticate = True | |
47 | ||
48 | self.ks_token_credential = self._create_ks_token_credential() | |
49 | ||
50 | super(KeystoneTokenTestCase, self).setUp() | |
51 | ||
52 | def test_get_token(self): | |
53 | self.assertEqual(self.token, | |
54 | self.ks_token_credential.token) | |
55 | ||
56 | def test_get_trust_id(self): | |
57 | self.assertEqual(self.trust_id, | |
58 | self.ks_token_credential.trust_id) | |
59 | ||
60 | def test_get_domain_id(self): | |
61 | self.assertEqual(self.domain_id, | |
62 | self.ks_token_credential.domain_id) | |
63 | ||
64 | def test_get_domain_name(self): | |
65 | self.assertEqual(self.domain_name, | |
66 | self.ks_token_credential.domain_name) | |
67 | ||
68 | def test_get_project_id(self): | |
69 | self.assertEqual(self.project_id, | |
70 | self.ks_token_credential.project_id) | |
71 | ||
72 | def test_get_project_name(self): | |
73 | self.assertEqual(self.project_name, | |
74 | self.ks_token_credential.project_name) | |
75 | ||
76 | def test_get_project_domain_id(self): | |
77 | self.assertEqual(self.project_domain_id, | |
78 | self.ks_token_credential.project_domain_id) | |
79 | ||
80 | def test_get_project_domain_name(self): | |
81 | self.assertEqual(self.project_domain_name, | |
82 | self.ks_token_credential.project_domain_name) | |
83 | ||
84 | def test_get_reauthenticate(self): | |
85 | self.assertEqual(self.reauthenticate, | |
86 | self.ks_token_credential.reauthenticate) | |
87 | ||
88 | def test___eq__(self): | |
89 | self.assertTrue(self.ks_token_credential == | |
90 | self.ks_token_credential) | |
91 | self.assertTrue(self.ks_token_credential is | |
92 | self.ks_token_credential) | |
93 | ||
94 | self.assertFalse(self.ks_token_credential is None) | |
95 | self.assertFalse(None == self.ks_token_credential) | |
96 | ||
97 | other_ks_token_credential = keystone_token.KeystoneToken( | |
98 | self.token, | |
99 | trust_id=self.trust_id, | |
100 | domain_id=self.domain_id, | |
101 | domain_name=self.domain_name, | |
102 | project_id=self.project_id, | |
103 | project_name=self.project_name, | |
104 | project_domain_id=self.project_domain_id, | |
105 | project_domain_name=self.project_domain_name, | |
106 | reauthenticate=self.reauthenticate) | |
107 | self.assertTrue(self.ks_token_credential == | |
108 | other_ks_token_credential) | |
109 | self.assertFalse(self.ks_token_credential is | |
110 | other_ks_token_credential) | |
111 | ||
112 | def test___ne___none(self): | |
113 | self.assertTrue(self.ks_token_credential is not None) | |
114 | self.assertTrue(None != self.ks_token_credential) | |
115 | ||
116 | def test___ne___token(self): | |
117 | other_token = "5c59e3217d3d4dd297589b297aee2a6f" | |
118 | ||
119 | other_ks_token_credential = keystone_token.KeystoneToken( | |
120 | other_token, | |
121 | trust_id=self.trust_id, | |
122 | domain_id=self.domain_id, | |
123 | domain_name=self.domain_name, | |
124 | project_id=self.project_id, | |
125 | project_name=self.project_name, | |
126 | project_domain_id=self.project_domain_id, | |
127 | project_domain_name=self.project_domain_name, | |
128 | reauthenticate=self.reauthenticate) | |
129 | ||
130 | self.assertTrue(self.ks_token_credential != | |
131 | other_ks_token_credential) | |
132 | ||
133 | def test___ne___trust_id(self): | |
134 | other_trust_id = "00000000000000" | |
135 | ||
136 | other_ks_token_credential = keystone_token.KeystoneToken( | |
137 | self.token, | |
138 | trust_id=other_trust_id, | |
139 | domain_id=self.domain_id, | |
140 | domain_name=self.domain_name, | |
141 | project_id=self.project_id, | |
142 | project_name=self.project_name, | |
143 | project_domain_id=self.project_domain_id, | |
144 | project_domain_name=self.project_domain_name, | |
145 | reauthenticate=self.reauthenticate) | |
146 | ||
147 | self.assertTrue(self.ks_token_credential != | |
148 | other_ks_token_credential) | |
149 | ||
150 | def test___ne___domain_id(self): | |
151 | other_domain_id = "domain0" | |
152 | ||
153 | other_ks_token_credential = keystone_token.KeystoneToken( | |
154 | self.token, | |
155 | trust_id=self.trust_id, | |
156 | domain_id=other_domain_id, | |
157 | domain_name=self.domain_name, | |
158 | project_id=self.project_id, | |
159 | project_name=self.project_name, | |
160 | project_domain_id=self.project_domain_id, | |
161 | project_domain_name=self.project_domain_name, | |
162 | reauthenticate=self.reauthenticate) | |
163 | ||
164 | self.assertTrue(self.ks_token_credential != | |
165 | other_ks_token_credential) | |
166 | ||
167 | def test___ne___domain_name(self): | |
168 | other_domain_name = "domain0" | |
169 | ||
170 | other_ks_token_credential = keystone_token.KeystoneToken( | |
171 | self.token, | |
172 | trust_id=self.trust_id, | |
173 | domain_id=self.domain_id, | |
174 | domain_name=other_domain_name, | |
175 | project_id=self.project_id, | |
176 | project_name=self.project_name, | |
177 | project_domain_id=self.project_domain_id, | |
178 | project_domain_name=self.project_domain_name, | |
179 | reauthenticate=self.reauthenticate) | |
180 | ||
181 | self.assertTrue(self.ks_token_credential != | |
182 | other_ks_token_credential) | |
183 | ||
184 | def test___ne___project_id(self): | |
185 | other_project_id = "00000000000000" | |
186 | ||
187 | other_ks_token_credential = keystone_token.KeystoneToken( | |
188 | self.token, | |
189 | trust_id=self.trust_id, | |
190 | domain_id=self.domain_id, | |
191 | domain_name=self.domain_name, | |
192 | project_id=other_project_id, | |
193 | project_name=self.project_name, | |
194 | project_domain_id=self.project_domain_id, | |
195 | project_domain_name=self.project_domain_name, | |
196 | reauthenticate=self.reauthenticate) | |
197 | ||
198 | self.assertTrue(self.ks_token_credential != | |
199 | other_ks_token_credential) | |
200 | ||
201 | def test___ne___project_name(self): | |
202 | other_project_name = "proj0" | |
203 | ||
204 | other_ks_token_credential = keystone_token.KeystoneToken( | |
205 | self.token, | |
206 | trust_id=self.trust_id, | |
207 | domain_id=self.domain_id, | |
208 | domain_name=self.domain_name, | |
209 | project_id=self.project_id, | |
210 | project_name=other_project_name, | |
211 | project_domain_id=self.project_domain_id, | |
212 | project_domain_name=self.project_domain_name, | |
213 | reauthenticate=self.reauthenticate) | |
214 | ||
215 | self.assertTrue(self.ks_token_credential != | |
216 | other_ks_token_credential) | |
217 | ||
218 | def test___ne___project_domain_id(self): | |
219 | other_project_domain_id = "domain0" | |
220 | ||
221 | other_ks_token_credential = keystone_token.KeystoneToken( | |
222 | self.token, | |
223 | trust_id=self.trust_id, | |
224 | domain_id=self.domain_id, | |
225 | domain_name=self.domain_name, | |
226 | project_id=self.project_id, | |
227 | project_name=self.project_name, | |
228 | project_domain_id=other_project_domain_id, | |
229 | project_domain_name=self.project_domain_name, | |
230 | reauthenticate=self.reauthenticate) | |
231 | ||
232 | self.assertTrue(self.ks_token_credential != | |
233 | other_ks_token_credential) | |
234 | ||
235 | def test___ne___project_domain_name(self): | |
236 | other_project_domain_name = "domain0" | |
237 | ||
238 | other_ks_token_credential = keystone_token.KeystoneToken( | |
239 | self.token, | |
240 | trust_id=self.trust_id, | |
241 | domain_id=self.domain_id, | |
242 | domain_name=self.domain_name, | |
243 | project_id=self.project_id, | |
244 | project_name=self.project_name, | |
245 | project_domain_id=self.project_domain_id, | |
246 | project_domain_name=other_project_domain_name, | |
247 | reauthenticate=self.reauthenticate) | |
248 | ||
249 | self.assertTrue(self.ks_token_credential != | |
250 | other_ks_token_credential) | |
251 | ||
252 | def test___ne___reauthenticate(self): | |
253 | other_reauthenticate = False | |
254 | ||
255 | other_ks_token_credential = keystone_token.KeystoneToken( | |
256 | self.token, | |
257 | trust_id=self.trust_id, | |
258 | domain_id=self.domain_id, | |
259 | domain_name=self.domain_name, | |
260 | project_id=self.project_id, | |
261 | project_name=self.project_name, | |
262 | project_domain_id=self.project_domain_id, | |
263 | project_domain_name=self.project_domain_name, | |
264 | reauthenticate=other_reauthenticate) | |
265 | ||
266 | self.assertTrue(self.ks_token_credential != | |
267 | other_ks_token_credential) |
0 | # Copyright (c) 2015 IBM | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | ||
15 | """ | |
16 | Test cases for the password credential | |
17 | """ | |
18 | ||
19 | from castellan.common.credentials import password | |
20 | from castellan.tests import base | |
21 | ||
22 | ||
23 | class PasswordTestCase(base.TestCase): | |
24 | ||
25 | def _create_password_credential(self): | |
26 | return password.Password(self.username, | |
27 | self.password) | |
28 | ||
29 | def setUp(self): | |
30 | self.username = "admin" | |
31 | self.password = "Pa$$w0rd1" | |
32 | ||
33 | self.password_credential = self._create_password_credential() | |
34 | ||
35 | super(PasswordTestCase, self).setUp() | |
36 | ||
37 | def test_get_username(self): | |
38 | self.assertEqual(self.username, self.password_credential.username) | |
39 | ||
40 | def test_get_password(self): | |
41 | self.assertEqual(self.password, self.password_credential.password) | |
42 | ||
43 | def test___eq__(self): | |
44 | self.assertTrue(self.password_credential == self.password_credential) | |
45 | self.assertTrue(self.password_credential is self.password_credential) | |
46 | ||
47 | self.assertFalse(self.password_credential is None) | |
48 | self.assertFalse(None == self.password_credential) | |
49 | ||
50 | other_password_credential = password.Password(self.username, | |
51 | self.password) | |
52 | self.assertTrue(self.password_credential == other_password_credential) | |
53 | self.assertFalse(self.password_credential is other_password_credential) | |
54 | ||
55 | def test___ne___none(self): | |
56 | self.assertTrue(self.password_credential is not None) | |
57 | self.assertTrue(None != self.password_credential) | |
58 | ||
59 | def test___ne___username(self): | |
60 | other_username = "service" | |
61 | other_password_credential = password.Password(other_username, | |
62 | self.password) | |
63 | self.assertTrue(self.password_credential != other_password_credential) | |
64 | ||
65 | def test___ne___password(self): | |
66 | other_password = "i143Cats" | |
67 | other_password_credential = password.Password(self.username, | |
68 | other_password) | |
69 | self.assertTrue(self.password_credential != other_password_credential) |
0 | # Copyright (c) 2015 IBM | |
1 | # All Rights Reserved. | |
2 | # | |
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | |
4 | # not use this file except in compliance with the License. You may obtain | |
5 | # a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
12 | # License for the specific language governing permissions and limitations | |
13 | # under the License. | |
14 | ||
15 | """ | |
16 | Test cases for the token credential | |
17 | """ | |
18 | ||
19 | from castellan.common.credentials import token | |
20 | from castellan.tests import base | |
21 | ||
22 | ||
23 | class TokenTestCase(base.TestCase): | |
24 | ||
25 | def _create_token_credential(self): | |
26 | return token.Token(self.token) | |
27 | ||
28 | def setUp(self): | |
29 | self.token = "8a4aa147d58141c39a7a22905b90ba4e" | |
30 | self.token_credential = self._create_token_credential() | |
31 | super(TokenTestCase, self).setUp() | |
32 | ||
33 | def test_get_token(self): | |
34 | self.assertEqual(self.token, self.token_credential.token) | |
35 | ||
36 | def test___eq__(self): | |
37 | self.assertTrue(self.token_credential == self.token_credential) | |
38 | self.assertTrue(self.token_credential is self.token_credential) | |
39 | ||
40 | self.assertFalse(self.token_credential is None) | |
41 | self.assertFalse(None == self.token_credential) | |
42 | ||
43 | other_token_credential = token.Token(self.token) | |
44 | self.assertTrue(self.token_credential == other_token_credential) | |
45 | self.assertFalse(self.token_credential is other_token_credential) | |
46 | ||
47 | def test___ne___none(self): | |
48 | self.assertTrue(self.token_credential is not None) | |
49 | self.assertTrue(None != self.token_credential) | |
50 | ||
51 | def test___ne___token(self): | |
52 | other_token = "fe32af1fe47e4744a48254e60ae80012" | |
53 | other_token_credential = token.Token(other_token) | |
54 | self.assertTrue(self.token_credential != other_token_credential) |
52 | 52 | This key manager is not suitable for use in production deployments. |
53 | 53 | """ |
54 | 54 | |
55 | def __init__(self): | |
55 | def __init__(self, configuration=None): | |
56 | self.conf = configuration | |
56 | 57 | self.keys = {} |
57 | 58 | |
58 | 59 | def _generate_hex_key(self, key_length): |
64 | 65 | |
65 | 66 | def _generate_key(self, **kwargs): |
66 | 67 | name = kwargs.get('name', None) |
68 | algorithm = kwargs.get('algorithm', 'AES') | |
67 | 69 | key_length = kwargs.get('key_length', 256) |
68 | 70 | _hex = self._generate_hex_key(key_length) |
69 | 71 | return sym_key.SymmetricKey( |
70 | 'AES', | |
72 | algorithm, | |
71 | 73 | key_length, |
72 | 74 | bytes(binascii.unhexlify(_hex)), |
73 | 75 | name) |
15 | 15 | """ |
16 | 16 | Test cases for the barbican key manager. |
17 | 17 | """ |
18 | import calendar | |
18 | 19 | |
19 | 20 | from barbicanclient import exceptions as barbican_exceptions |
20 | 21 | import mock |
21 | 22 | from oslo_config import cfg |
23 | from oslo_utils import timeutils | |
22 | 24 | |
23 | 25 | from castellan.common import exception |
24 | 26 | from castellan.common.objects import symmetric_key as sym_key |
186 | 188 | original_secret_metadata.bit_length = mock.sentinel.bit |
187 | 189 | original_secret_metadata.secret_type = 'symmetric' |
188 | 190 | |
191 | created = timeutils.parse_isotime('2015-10-20 18:51:17+00:00') | |
192 | original_secret_metadata.created = created | |
193 | created_formatted = timeutils.parse_isotime(str(created)) | |
194 | created_posix = calendar.timegm(created_formatted.timetuple()) | |
195 | ||
189 | 196 | key_name = 'my key' |
190 | 197 | original_secret_metadata.name = key_name |
191 | 198 | |
198 | 205 | self.get.assert_called_once_with(self.secret_ref) |
199 | 206 | self.assertEqual(key_name, key.name) |
200 | 207 | self.assertEqual(original_secret_data, key.get_encoded()) |
208 | self.assertEqual(created_posix, key.created) | |
201 | 209 | |
202 | 210 | def test_get_null_context(self): |
203 | 211 | self.key_mgr._barbican_client = None |
320 | 328 | |
321 | 329 | self.assertEqual(number_of_retries + 1, |
322 | 330 | self.mock_barbican.orders.get.call_count) |
331 | ||
332 | def test_get_active_order_error(self): | |
333 | order_ref_url = ("http://localhost:9311/v1/orders/" | |
334 | "4fe939b7-72bc-49aa-bd1e-e979589858af") | |
335 | ||
336 | error_order = mock.Mock() | |
337 | error_order.status = u'ERROR' | |
338 | error_order.order_ref = order_ref_url | |
339 | error_order.error_status_code = u"500" | |
340 | error_order.error_reason = u"Test Error" | |
341 | ||
342 | self.mock_barbican.orders.get.return_value = error_order | |
343 | ||
344 | self.assertRaises(exception.KeyManagerError, | |
345 | self.key_mgr._get_active_order, | |
346 | self.mock_barbican, | |
347 | order_ref_url) | |
348 | ||
349 | self.assertEqual(1, self.mock_barbican.orders.get.call_count) |
70 | 70 | key_id = self.key_mgr.create_key(self.context, name=name) |
71 | 71 | key = self.key_mgr.get(self.context, key_id) |
72 | 72 | self.assertEqual(name, key.name) |
73 | ||
74 | def test_create_key_with_algorithm(self): | |
75 | algorithm = 'DES' | |
76 | key_id = self.key_mgr.create_key(self.context, algorithm=algorithm) | |
77 | key = self.key_mgr.get(self.context, key_id) | |
78 | self.assertEqual(algorithm, key.algorithm) | |
73 | 79 | |
74 | 80 | def test_create_key_null_context(self): |
75 | 81 | self.assertRaises(exception.Forbidden, |
15 | 15 | """ |
16 | 16 | Test cases for the opaque data class. |
17 | 17 | """ |
18 | ||
19 | 18 | from castellan.common.objects import opaque_data |
20 | 19 | from castellan.tests import base |
21 | 20 | |
23 | 22 | class OpaqueDataTestCase(base.TestCase): |
24 | 23 | |
25 | 24 | def _create_data(self): |
26 | return opaque_data.OpaqueData(self.data, self.name) | |
25 | return opaque_data.OpaqueData(self.data, | |
26 | self.name, | |
27 | self.created) | |
27 | 28 | |
28 | 29 | def setUp(self): |
29 | 30 | self.data = bytes(b"secret opaque data") |
30 | 31 | self.name = 'my opaque' |
32 | self.created = 1448088699 | |
31 | 33 | self.opaque_data = self._create_data() |
32 | 34 | |
33 | 35 | super(OpaqueDataTestCase, self).setUp() |
41 | 43 | def test_get_name(self): |
42 | 44 | self.assertEqual(self.name, self.opaque_data.name) |
43 | 45 | |
46 | def test_get_created(self): | |
47 | self.assertEqual(self.created, self.opaque_data.created) | |
48 | ||
49 | def test_get_created_none(self): | |
50 | created = None | |
51 | data = opaque_data.OpaqueData(self.data, | |
52 | self.name, | |
53 | created) | |
54 | ||
55 | self.assertEqual(created, data.created) | |
56 | ||
44 | 57 | def test___eq__(self): |
45 | 58 | self.assertTrue(self.opaque_data == self.opaque_data) |
46 | 59 | self.assertTrue(self.opaque_data is self.opaque_data) |
48 | 61 | self.assertFalse(self.opaque_data is None) |
49 | 62 | self.assertFalse(None == self.opaque_data) |
50 | 63 | |
51 | other_opaque_data = opaque_data.OpaqueData(self.data, self.name) | |
64 | other_opaque_data = opaque_data.OpaqueData(self.data) | |
52 | 65 | self.assertTrue(self.opaque_data == other_opaque_data) |
53 | 66 | self.assertFalse(self.opaque_data is other_opaque_data) |
54 | 67 | |
59 | 72 | def test___ne___data(self): |
60 | 73 | other_opaque = opaque_data.OpaqueData(b'other data', self.name) |
61 | 74 | self.assertTrue(self.opaque_data != other_opaque) |
62 | ||
63 | def test___ne___name(self): | |
64 | other_opaque = opaque_data.OpaqueData(self.data, "other opaque") | |
65 | self.assertTrue(self.opaque_data != other_opaque) |
15 | 15 | """ |
16 | 16 | Test cases for the passphrase class. |
17 | 17 | """ |
18 | ||
19 | 18 | from castellan.common.objects import passphrase |
20 | 19 | from castellan.tests import base |
21 | 20 | |
24 | 23 | |
25 | 24 | def _create_passphrase(self): |
26 | 25 | return passphrase.Passphrase(self.passphrase_data, |
27 | self.name) | |
26 | self.name, | |
27 | self.created) | |
28 | 28 | |
29 | 29 | def setUp(self): |
30 | 30 | self.passphrase_data = bytes(b"secret passphrase") |
31 | 31 | self.name = 'my phrase' |
32 | self.created = 1448088699 | |
32 | 33 | self.passphrase = self._create_passphrase() |
33 | 34 | |
34 | 35 | super(PassphraseTestCase, self).setUp() |
42 | 43 | def test_get_name(self): |
43 | 44 | self.assertEqual(self.name, self.passphrase.name) |
44 | 45 | |
46 | def test_get_created(self): | |
47 | self.assertEqual(self.created, self.passphrase.created) | |
48 | ||
49 | def test_get_created_none(self): | |
50 | created = None | |
51 | phrase = passphrase.Passphrase(self.passphrase_data, | |
52 | self.name, | |
53 | created) | |
54 | ||
55 | self.assertEqual(created, phrase.created) | |
56 | ||
45 | 57 | def test___eq__(self): |
46 | 58 | self.assertTrue(self.passphrase == self.passphrase) |
47 | 59 | self.assertTrue(self.passphrase is self.passphrase) |
49 | 61 | self.assertFalse(self.passphrase is None) |
50 | 62 | self.assertFalse(None == self.passphrase) |
51 | 63 | |
52 | other_passphrase = passphrase.Passphrase(self.passphrase_data, | |
53 | self.name) | |
64 | other_passphrase = passphrase.Passphrase(self.passphrase_data) | |
54 | 65 | self.assertTrue(self.passphrase == other_passphrase) |
55 | 66 | self.assertFalse(self.passphrase is other_passphrase) |
56 | 67 | |
61 | 72 | def test___ne___data(self): |
62 | 73 | other_phrase = passphrase.Passphrase(b"other passphrase", self.name) |
63 | 74 | self.assertTrue(self.passphrase != other_phrase) |
64 | ||
65 | def test___ne__name(self): | |
66 | other_phrase = passphrase.Passphrase(self.passphrase_data, | |
67 | "other phrase") | |
68 | self.assertTrue(self.passphrase != other_phrase) |
15 | 15 | """ |
16 | 16 | Test cases for the private key class. |
17 | 17 | """ |
18 | ||
19 | 18 | from castellan.common.objects import private_key |
20 | 19 | from castellan.tests import base |
21 | 20 | from castellan.tests import utils |
25 | 24 | |
26 | 25 | def _create_key(self): |
27 | 26 | return private_key.PrivateKey(self.algorithm, |
28 | self.length, | |
27 | self.bit_length, | |
29 | 28 | self.encoded, |
30 | self.name) | |
29 | self.name, | |
30 | self.created) | |
31 | 31 | |
32 | 32 | def setUp(self): |
33 | 33 | self.algorithm = 'RSA' |
34 | self.length = 2048 | |
34 | self.bit_length = 2048 | |
35 | 35 | self.encoded = bytes(utils.get_private_key_der()) |
36 | 36 | self.name = 'my key' |
37 | self.created = 1448088699 | |
37 | 38 | |
38 | 39 | super(PrivateKeyTestCase, self).setUp() |
39 | 40 | |
40 | 41 | def test_get_algorithm(self): |
41 | 42 | self.assertEqual(self.algorithm, self.key.algorithm) |
42 | 43 | |
43 | def test_get_length(self): | |
44 | self.assertEqual(self.length, self.key.bit_length) | |
44 | def test_get_bit_length(self): | |
45 | self.assertEqual(self.bit_length, self.key.bit_length) | |
45 | 46 | |
46 | 47 | def test_get_name(self): |
47 | 48 | self.assertEqual(self.name, self.key.name) |
52 | 53 | def test_get_encoded(self): |
53 | 54 | self.assertEqual(self.encoded, self.key.get_encoded()) |
54 | 55 | |
56 | def test_get_created(self): | |
57 | self.assertEqual(self.created, self.key.created) | |
58 | ||
59 | def test_get_created_none(self): | |
60 | created = None | |
61 | key = private_key.PrivateKey(self.algorithm, | |
62 | self.bit_length, | |
63 | self.encoded, | |
64 | self.name, | |
65 | created) | |
66 | ||
67 | self.assertEqual(created, key.created) | |
68 | ||
55 | 69 | def test___eq__(self): |
56 | 70 | self.assertTrue(self.key == self.key) |
57 | 71 | self.assertTrue(self.key is self.key) |
60 | 74 | self.assertFalse(None == self.key) |
61 | 75 | |
62 | 76 | other_key = private_key.PrivateKey(self.algorithm, |
63 | self.length, | |
64 | self.encoded, | |
65 | self.name) | |
77 | self.bit_length, | |
78 | self.encoded) | |
66 | 79 | self.assertTrue(self.key == other_key) |
67 | 80 | self.assertFalse(self.key is other_key) |
68 | 81 | |
72 | 85 | |
73 | 86 | def test___ne___algorithm(self): |
74 | 87 | other_key = private_key.PrivateKey('DSA', |
75 | self.length, | |
88 | self.bit_length, | |
76 | 89 | self.encoded, |
77 | 90 | self.name) |
78 | 91 | self.assertTrue(self.key != other_key) |
79 | 92 | |
80 | def test___ne___length(self): | |
93 | def test___ne___bit_length(self): | |
81 | 94 | other_key = private_key.PrivateKey(self.algorithm, |
82 | 95 | 4096, |
83 | 96 | self.encoded, |
87 | 100 | def test___ne___encoded(self): |
88 | 101 | different_encoded = bytes(utils.get_private_key_der()) + b'\x00' |
89 | 102 | other_key = private_key.PrivateKey(self.algorithm, |
90 | self.length, | |
103 | self.bit_length, | |
91 | 104 | different_encoded, |
92 | 105 | self.name) |
93 | 106 | self.assertTrue(self.key != other_key) |
94 | ||
95 | def test___ne___name(self): | |
96 | other_key = private_key.PrivateKey(self.algorithm, | |
97 | self.length, | |
98 | self.encoded, | |
99 | 'other key') | |
100 | self.assertTrue(self.key != other_key) |
15 | 15 | """ |
16 | 16 | Test cases for the public key class. |
17 | 17 | """ |
18 | ||
19 | 18 | from castellan.common.objects import public_key |
20 | 19 | from castellan.tests import base |
21 | 20 | from castellan.tests import utils |
25 | 24 | |
26 | 25 | def _create_key(self): |
27 | 26 | return public_key.PublicKey(self.algorithm, |
28 | self.length, | |
27 | self.bit_length, | |
29 | 28 | self.encoded, |
30 | self.name) | |
29 | self.name, | |
30 | self.created) | |
31 | 31 | |
32 | 32 | def setUp(self): |
33 | 33 | self.algorithm = 'RSA' |
34 | self.length = 2048 | |
34 | self.bit_length = 2048 | |
35 | 35 | self.encoded = bytes(utils.get_public_key_der()) |
36 | 36 | self.name = 'my key' |
37 | self.created = 1448088699 | |
37 | 38 | |
38 | 39 | super(PublicKeyTestCase, self).setUp() |
39 | 40 | |
40 | 41 | def test_get_algorithm(self): |
41 | 42 | self.assertEqual(self.algorithm, self.key.algorithm) |
42 | 43 | |
43 | def test_get_length(self): | |
44 | self.assertEqual(self.length, self.key.bit_length) | |
44 | def test_get_bit_length(self): | |
45 | self.assertEqual(self.bit_length, self.key.bit_length) | |
45 | 46 | |
46 | 47 | def test_get_name(self): |
47 | 48 | self.assertEqual(self.name, self.key.name) |
52 | 53 | def test_get_encoded(self): |
53 | 54 | self.assertEqual(self.encoded, self.key.get_encoded()) |
54 | 55 | |
56 | def test_get_created(self): | |
57 | self.assertEqual(self.created, self.key.created) | |
58 | ||
59 | def test_get_created_none(self): | |
60 | created = None | |
61 | key = public_key.PublicKey(self.algorithm, | |
62 | self.bit_length, | |
63 | self.encoded, | |
64 | self.name, | |
65 | created) | |
66 | ||
67 | self.assertEqual(created, key.created) | |
68 | ||
55 | 69 | def test___eq__(self): |
56 | 70 | self.assertTrue(self.key == self.key) |
57 | 71 | self.assertTrue(self.key is self.key) |
60 | 74 | self.assertFalse(None == self.key) |
61 | 75 | |
62 | 76 | other_key = public_key.PublicKey(self.algorithm, |
63 | self.length, | |
64 | self.encoded, | |
65 | self.name) | |
77 | self.bit_length, | |
78 | self.encoded) | |
66 | 79 | self.assertTrue(self.key == other_key) |
67 | 80 | self.assertFalse(self.key is other_key) |
68 | 81 | |
72 | 85 | |
73 | 86 | def test___ne___algorithm(self): |
74 | 87 | other_key = public_key.PublicKey('DSA', |
75 | self.length, | |
88 | self.bit_length, | |
76 | 89 | self.encoded, |
77 | 90 | self.name) |
78 | 91 | self.assertTrue(self.key != other_key) |
79 | 92 | |
80 | def test___ne___length(self): | |
93 | def test___ne___bit_length(self): | |
81 | 94 | other_key = public_key.PublicKey(self.algorithm, |
82 | 95 | 4096, |
83 | 96 | self.encoded, |
87 | 100 | def test___ne___encoded(self): |
88 | 101 | different_encoded = bytes(utils.get_public_key_der()) + b'\x00' |
89 | 102 | other_key = public_key.PublicKey(self.algorithm, |
90 | self.length, | |
103 | self.bit_length, | |
91 | 104 | different_encoded, |
92 | 105 | self.name) |
93 | 106 | self.assertTrue(self.key != other_key) |
94 | ||
95 | def test___ne__name(self): | |
96 | other_key = public_key.PublicKey(self.algorithm, | |
97 | self.length, | |
98 | self.encoded, | |
99 | 'other key') | |
100 | self.assertTrue(self.key != other_key) |
15 | 15 | """ |
16 | 16 | Test cases for the symmetric key class. |
17 | 17 | """ |
18 | ||
19 | 18 | from castellan.common.objects import symmetric_key as sym_key |
20 | 19 | from castellan.tests import base |
21 | 20 | |
26 | 25 | return sym_key.SymmetricKey(self.algorithm, |
27 | 26 | self.bit_length, |
28 | 27 | self.encoded, |
29 | self.name) | |
28 | self.name, | |
29 | self.created) | |
30 | 30 | |
31 | 31 | def setUp(self): |
32 | 32 | self.algorithm = 'AES' |
33 | 33 | self.encoded = bytes(b'0' * 64) |
34 | 34 | self.bit_length = len(self.encoded) * 8 |
35 | 35 | self.name = 'my key' |
36 | self.created = 1448088699 | |
36 | 37 | |
37 | 38 | super(SymmetricKeyTestCase, self).setUp() |
38 | 39 | |
51 | 52 | def test_get_bit_length(self): |
52 | 53 | self.assertEqual(self.bit_length, self.key.bit_length) |
53 | 54 | |
55 | def test_get_created(self): | |
56 | self.assertEqual(self.created, self.key.created) | |
57 | ||
58 | def test_get_created_none(self): | |
59 | created = None | |
60 | key = sym_key.SymmetricKey(self.algorithm, | |
61 | self.bit_length, | |
62 | self.encoded, | |
63 | self.name, | |
64 | created) | |
65 | ||
66 | self.assertEqual(created, key.created) | |
67 | ||
54 | 68 | def test___eq__(self): |
55 | 69 | self.assertTrue(self.key == self.key) |
56 | 70 | self.assertTrue(self.key is self.key) |
60 | 74 | |
61 | 75 | other_key = sym_key.SymmetricKey(self.algorithm, |
62 | 76 | self.bit_length, |
63 | self.encoded, | |
64 | self.name) | |
77 | self.encoded) | |
65 | 78 | self.assertTrue(self.key == other_key) |
66 | 79 | self.assertFalse(self.key is other_key) |
67 | 80 | |
76 | 89 | self.name) |
77 | 90 | self.assertTrue(self.key != other_key) |
78 | 91 | |
79 | def test___ne___length(self): | |
92 | def test___ne___bit_length(self): | |
80 | 93 | other_key = sym_key.SymmetricKey(self.algorithm, |
81 | 94 | self.bit_length * 2, |
82 | 95 | self.encoded, |
90 | 103 | different_encoded, |
91 | 104 | self.name) |
92 | 105 | self.assertTrue(self.key != other_key) |
93 | ||
94 | def test___ne___name(self): | |
95 | other_key = sym_key.SymmetricKey(self.algorithm, | |
96 | self.bit_length, | |
97 | self.encoded, | |
98 | 'other key') | |
99 | self.assertTrue(self.key != other_key) |
15 | 15 | """ |
16 | 16 | Test cases for the X.509 certificate class. |
17 | 17 | """ |
18 | ||
19 | 18 | from castellan.common.objects import x_509 |
20 | 19 | from castellan.tests import base |
21 | 20 | from castellan.tests import utils |
24 | 23 | class X509TestCase(base.CertificateTestCase): |
25 | 24 | |
26 | 25 | def _create_cert(self): |
27 | return x_509.X509(self.data, self.name) | |
26 | return x_509.X509(self.data, | |
27 | self.name, | |
28 | self.created) | |
28 | 29 | |
29 | 30 | def setUp(self): |
30 | 31 | self.data = utils.get_certificate_der() |
31 | 32 | self.name = 'my cert' |
33 | self.created = 1448088699 | |
32 | 34 | |
33 | 35 | super(X509TestCase, self).setUp() |
34 | 36 | |
41 | 43 | def test_get_encoded(self): |
42 | 44 | self.assertEqual(self.data, self.cert.get_encoded()) |
43 | 45 | |
46 | def test_get_created(self): | |
47 | self.assertEqual(self.created, self.cert.created) | |
48 | ||
49 | def test_get_created_none(self): | |
50 | created = None | |
51 | cert = x_509.X509(self.data, | |
52 | self.name, | |
53 | created) | |
54 | ||
55 | self.assertEqual(created, cert.created) | |
56 | ||
44 | 57 | def test___eq__(self): |
45 | 58 | self.assertTrue(self.cert == self.cert) |
46 | 59 | self.assertTrue(self.cert is self.cert) |
48 | 61 | self.assertFalse(self.cert is None) |
49 | 62 | self.assertFalse(None == self.cert) |
50 | 63 | |
51 | other_x_509 = x_509.X509(self.data, self.name) | |
64 | other_x_509 = x_509.X509(self.data) | |
52 | 65 | self.assertTrue(self.cert == other_x_509) |
53 | 66 | self.assertFalse(self.cert is other_x_509) |
54 | 67 | |
59 | 72 | def test___ne___data(self): |
60 | 73 | other_x509 = x_509.X509(b'\x00\x00\x00', self.name) |
61 | 74 | self.assertTrue(self.cert != other_x509) |
62 | ||
63 | def test___ne__name(self): | |
64 | other_x509 = x_509.X509(self.data, "other x509") | |
65 | self.assertTrue(self.cert != other_x509) |
0 | # Copyright (c) 2016 IBM | |
1 | # Licensed under the Apache License, Version 2.0 (the "License"); | |
2 | # you may not use this file except in compliance with the License. | |
3 | # You may obtain a copy of the License at | |
4 | # | |
5 | # http://www.apache.org/licenses/LICENSE-2.0 | |
6 | # | |
7 | # Unless required by applicable law or agreed to in writing, software | |
8 | # distributed under the License is distributed on an "AS IS" BASIS, | |
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
10 | # implied. | |
11 | # See the License for the specific language governing permissions and | |
12 | # limitations under the License. | |
13 | ||
14 | """ | |
15 | Test Common utilities for Castellan. | |
16 | """ | |
17 | ||
18 | from castellan.common import exception | |
19 | from castellan.common import utils | |
20 | from castellan.tests import base | |
21 | ||
22 | from oslo_config import cfg | |
23 | from oslo_config import fixture as config_fixture | |
24 | from oslo_context import context | |
25 | ||
26 | CONF = cfg.CONF | |
27 | ||
28 | ||
29 | class TestUtils(base.TestCase): | |
30 | ||
31 | def setUp(self): | |
32 | super(TestUtils, self).setUp() | |
33 | self.config_fixture = self.useFixture(config_fixture.Config(CONF)) | |
34 | CONF.register_opts(utils.credential_opts, group=utils.OPT_GROUP) | |
35 | ||
36 | def test_token_credential(self): | |
37 | token_value = 'ec9799cd921e4e0a8ab6111c08ebf065' | |
38 | ||
39 | self.config_fixture.config( | |
40 | auth_type='token', | |
41 | token=token_value, | |
42 | group='key_manager' | |
43 | ) | |
44 | ||
45 | token_context = utils.credential_factory(conf=CONF) | |
46 | token_context_class = token_context.__class__.__name__ | |
47 | ||
48 | self.assertEqual('Token', token_context_class) | |
49 | self.assertEqual(token_value, token_context.token) | |
50 | ||
51 | def test_token_credential_with_context(self): | |
52 | token_value = 'ec9799cd921e4e0a8ab6111c08ebf065' | |
53 | ctxt = context.RequestContext(auth_token=token_value) | |
54 | ||
55 | self.config_fixture.config( | |
56 | auth_type='token', | |
57 | group='key_manager' | |
58 | ) | |
59 | ||
60 | token_context = utils.credential_factory(conf=CONF, context=ctxt) | |
61 | token_context_class = token_context.__class__.__name__ | |
62 | ||
63 | self.assertEqual('Token', token_context_class) | |
64 | self.assertEqual(token_value, token_context.token) | |
65 | ||
66 | def test_token_credential_config_override_context(self): | |
67 | ctxt_token_value = '00000000000000000000000000000000' | |
68 | ctxt = context.RequestContext(auth_token=ctxt_token_value) | |
69 | ||
70 | conf_token_value = 'ec9799cd921e4e0a8ab6111c08ebf065' | |
71 | ||
72 | self.config_fixture.config( | |
73 | auth_type='token', | |
74 | token=conf_token_value, | |
75 | group='key_manager' | |
76 | ) | |
77 | ||
78 | token_context = utils.credential_factory(conf=CONF, context=ctxt) | |
79 | token_context_class = token_context.__class__.__name__ | |
80 | ||
81 | self.assertEqual('Token', token_context_class) | |
82 | self.assertEqual(conf_token_value, token_context.token) | |
83 | ||
84 | def test_token_credential_exception(self): | |
85 | self.config_fixture.config( | |
86 | auth_type='token', | |
87 | group='key_manager' | |
88 | ) | |
89 | ||
90 | self.assertRaises(exception.InsufficientCredentialDataError, | |
91 | utils.credential_factory, | |
92 | CONF) | |
93 | ||
94 | def test_password_credential(self): | |
95 | password_value = 'p4ssw0rd' | |
96 | ||
97 | self.config_fixture.config( | |
98 | auth_type='password', | |
99 | password=password_value, | |
100 | group='key_manager' | |
101 | ) | |
102 | ||
103 | password_context = utils.credential_factory(conf=CONF) | |
104 | password_context_class = password_context.__class__.__name__ | |
105 | ||
106 | self.assertEqual('Password', password_context_class) | |
107 | self.assertEqual(password_value, password_context.password) | |
108 | ||
109 | def test_keystone_token_credential(self): | |
110 | token_value = 'ec9799cd921e4e0a8ab6111c08ebf065' | |
111 | ||
112 | self.config_fixture.config( | |
113 | auth_type='keystone_token', | |
114 | token=token_value, | |
115 | group='key_manager' | |
116 | ) | |
117 | ||
118 | ks_token_context = utils.credential_factory(conf=CONF) | |
119 | ks_token_context_class = ks_token_context.__class__.__name__ | |
120 | ||
121 | self.assertEqual('KeystoneToken', ks_token_context_class) | |
122 | self.assertEqual(token_value, ks_token_context.token) | |
123 | ||
124 | def test_keystone_token_credential_with_context(self): | |
125 | token_value = 'ec9799cd921e4e0a8ab6111c08ebf065' | |
126 | ctxt = context.RequestContext(auth_token=token_value) | |
127 | ||
128 | self.config_fixture.config( | |
129 | auth_type='keystone_token', | |
130 | group='key_manager' | |
131 | ) | |
132 | ||
133 | ks_token_context = utils.credential_factory(conf=CONF, context=ctxt) | |
134 | ks_token_context_class = ks_token_context.__class__.__name__ | |
135 | ||
136 | self.assertEqual('KeystoneToken', ks_token_context_class) | |
137 | self.assertEqual(token_value, ks_token_context.token) | |
138 | ||
139 | def test_keystone_token_credential_config_override_context(self): | |
140 | ctxt_token_value = 'ec9799cd921e4e0a8ab6111c08ebf065' | |
141 | ctxt = context.RequestContext(auth_token=ctxt_token_value) | |
142 | ||
143 | conf_token_value = 'ec9799cd921e4e0a8ab6111c08ebf065' | |
144 | ||
145 | self.config_fixture.config( | |
146 | auth_type='keystone_token', | |
147 | token=conf_token_value, | |
148 | group='key_manager' | |
149 | ) | |
150 | ||
151 | ks_token_context = utils.credential_factory(conf=CONF, context=ctxt) | |
152 | ks_token_context_class = ks_token_context.__class__.__name__ | |
153 | ||
154 | self.assertEqual('KeystoneToken', ks_token_context_class) | |
155 | self.assertEqual(conf_token_value, ks_token_context.token) | |
156 | ||
157 | def test_keystone_token_credential_exception(self): | |
158 | self.config_fixture.config( | |
159 | auth_type='keystone_token', | |
160 | group='key_manager' | |
161 | ) | |
162 | ||
163 | self.assertRaises(exception.InsufficientCredentialDataError, | |
164 | utils.credential_factory, | |
165 | CONF) | |
166 | ||
167 | def test_keystone_password_credential(self): | |
168 | password_value = 'p4ssw0rd' | |
169 | ||
170 | self.config_fixture.config( | |
171 | auth_type='keystone_password', | |
172 | password=password_value, | |
173 | group='key_manager' | |
174 | ) | |
175 | ||
176 | ks_password_context = utils.credential_factory(conf=CONF) | |
177 | ks_password_context_class = ks_password_context.__class__.__name__ | |
178 | ||
179 | self.assertEqual('KeystonePassword', ks_password_context_class) | |
180 | self.assertEqual(password_value, ks_password_context.password) | |
181 | ||
182 | def test_oslo_context_to_keystone_token(self): | |
183 | auth_token_value = '16bd612f28ec479b8ffe8e124fc37b43' | |
184 | tenant_value = '00c6ef5ad2984af2acd7d42c299935c0' | |
185 | ||
186 | ctxt = context.RequestContext( | |
187 | auth_token=auth_token_value, | |
188 | tenant=tenant_value) | |
189 | ||
190 | ks_token_context = utils.credential_factory(context=ctxt) | |
191 | ks_token_context_class = ks_token_context.__class__.__name__ | |
192 | ||
193 | self.assertEqual('KeystoneToken', ks_token_context_class) | |
194 | self.assertEqual(auth_token_value, ks_token_context.token) | |
195 | self.assertEqual(tenant_value, ks_token_context.project_id) | |
196 | ||
197 | def test_invalid_auth_type(self): | |
198 | self.config_fixture.config( | |
199 | auth_type='hotdog', | |
200 | group='key_manager' | |
201 | ) | |
202 | ||
203 | self.assertRaises(exception.AuthTypeInvalidError, | |
204 | utils.credential_factory, | |
205 | conf=CONF) |
6 | 6 | consider the key manager behavior you wish to encapsulate and the OpenStack |
7 | 7 | deployments on which your application will run. |
8 | 8 | |
9 | Basic usage | |
10 | ~~~~~~~~~~~ | |
11 | ||
12 | Castellan works on the principle of providing an abstracted key manager based | |
13 | on your configuration. In this manner, several different management services | |
14 | can be supported through a single interface. | |
15 | ||
16 | In addition to the key manager, Castellan also provides primitives for | |
17 | various types of secrets (for example, asymmetric keys, simple passphrases, | |
18 | and certificates). These primitives are used in conjunction with the key | |
19 | manager to create, store, retrieve, and destroy managed secrets. | |
20 | ||
21 | Another fundamental concept to using Castellan is the context object, most | |
9 | Authentication | |
10 | ~~~~~~~~~~~~~~ | |
11 | ||
12 | A fundamental concept to using Castellan is the credential context object. | |
13 | Castellan supports the following credentials for authentication: | |
14 | ||
15 | * Token | |
16 | * Password | |
17 | * Keystone Token | |
18 | * Keystone Password | |
19 | ||
20 | In order to use these credentials, valid configuration parameters must be | |
21 | provided. | |
22 | ||
23 | .. code:: ini | |
24 | ||
25 | # token credential | |
26 | # token variable not required, token can be obtained from context | |
27 | [castellan] | |
28 | auth_type = 'token' | |
29 | token = '5b4de0bb77064f289f7cc58e33bea8c7' | |
30 | ||
31 | # password credential | |
32 | [castellan] | |
33 | auth_type = 'password' | |
34 | username = 'admin' | |
35 | password = 'passw0rd1' | |
36 | ||
37 | # keystone token credential | |
38 | [castellan] | |
39 | auth_type = 'keystone_token' | |
40 | token = '5b4de0bb77064f289f7cc58e33bea8c7' | |
41 | project_id = 'a1e19934af81420d980a5d02b4afe9fb' | |
42 | ||
43 | # keystone password credential | |
44 | [castellan] | |
45 | auth_type = 'keystone_password' | |
46 | username = 'admin' | |
47 | password = 'passw0rd1' | |
48 | project_id = '1099302ec608486f9879ba2466c60720' | |
49 | user_domain_name = 'default' | |
50 | ||
51 | .. note:: | |
52 | ||
53 | Keystone Token and Password authentication is achieved using | |
54 | keystoneclient.auth.identity.v3 Token and Password auth plugins. | |
55 | There are a variety of different variables which can be set for the | |
56 | keystone credential options. | |
57 | ||
58 | ||
59 | The configuration must be passed to a credential factory which will | |
60 | generate the appropriate context. | |
61 | ||
62 | .. code:: python | |
63 | ||
64 | from castellan.common import utils | |
65 | ||
66 | CONF = <your_configuration> | |
67 | context = utils.credential_factory(conf=CONF, context=None) | |
68 | ||
69 | Now you can go ahead and pass the context and use it for authentication. | |
70 | ||
71 | .. note:: | |
72 | ||
73 | There is a special case for a token. Since a user may not want to store a | |
74 | token in the configuration, the user can pass a context object containing | |
75 | an 'auth_token' as well as a configuration file with 'token' as the | |
76 | auth type. | |
77 | ||
78 | ||
79 | An oslo context object can also be used for authentication, it is | |
22 | 80 | frequently inherited from ``oslo.context.RequestContext``. This object |
23 | 81 | represents information that is contained in the current request, and is |
24 | 82 | usually populated in the WSGI pipeline. The information contained in this |
47 | 105 | ctxt = context.RequestContext(auth_token=keystone_client.auth_token, |
48 | 106 | tenant=project_list[0].id) |
49 | 107 | |
50 | ctxt can then be passed into any key_manager api call which requires | |
51 | a RequestContext object. | |
108 | ctxt can then be passed into any key_manager api call. | |
109 | ||
110 | ||
111 | Basic usage | |
112 | ~~~~~~~~~~~ | |
113 | ||
114 | Castellan works on the principle of providing an abstracted key manager based | |
115 | on your configuration. In this manner, several different management services | |
116 | can be supported through a single interface. | |
117 | ||
118 | In addition to the key manager, Castellan also provides primitives for | |
119 | various types of secrets (for example, asymmetric keys, simple passphrases, | |
120 | and certificates). These primitives are used in conjunction with the key | |
121 | manager to create, store, retrieve, and destroy managed secrets. | |
52 | 122 | |
53 | 123 | **Example. Creating and storing a key.** |
54 | 124 | |
192 | 262 | .. code:: console |
193 | 263 | |
194 | 264 | $ tox -e genconfig |
265 | ||
266 | ||
267 | Parsing the configuration files | |
268 | ------------------------------- | |
269 | ||
270 | Castellan does not parse the configuration files by default. When you create | |
271 | the files and occupy them, you still need to manipulate the | |
272 | ``oslo_config.cfg.ConfigOpts`` object before passing it to the | |
273 | ``castellan.key_manager.API`` object. You can create a list of locations where | |
274 | the configuration files reside. If multiple configuration files are | |
275 | specified, the variables will be used from the most recently parsed file and | |
276 | overwrite any previous variables. In the example below, the configuration | |
277 | file in the ``/etc/castellan`` directory will overwrite the values found in | |
278 | the file in the user's home directory. If a file is not found in one of the | |
279 | specified locations, then a file not found error will occur. | |
280 | ||
281 | **Example. Parsing the config files.** | |
282 | ||
283 | .. code:: python | |
284 | ||
285 | from oslo_config import cfg | |
286 | from castellan import key_manager | |
287 | ||
288 | conf = cfg.ConfigOpts() | |
289 | conf(['~/castellan.conf', '/etc/castellan/castellan.conf']) | |
290 | manager = key_manager.API(configuration=conf) | |
291 | ||
292 | There are two options for parsing the Castellan values from a | |
293 | configuration file: | |
294 | ||
295 | - The values can be placed in a separate file. | |
296 | - You can include the values in a configuration file you already use. | |
297 | ||
298 | In order to see all of the default values used by Castellan, generate a | |
299 | sample configuration by referring to the section directly above. | |
195 | 300 | |
196 | 301 | Adding castellan to configuration files |
197 | 302 | --------------------------------------- |
1 | 1 | # of appearance. Changing the order has an impact on the overall integration |
2 | 2 | # process, which may cause wedges in the gate later. |
3 | 3 | |
4 | pbr>=1.6 | |
5 | Babel>=1.3 | |
6 | cryptography>=1.0 # Apache-2.0 | |
7 | oslo.config>=2.7.0 # Apache-2.0 | |
4 | pbr>=1.6 # Apache-2.0 | |
5 | Babel>=1.3 # BSD | |
6 | cryptography>=1.0 # BSD/Apache-2.0 | |
7 | oslo.config>=3.7.0 # Apache-2.0 | |
8 | 8 | oslo.context>=0.2.0 # Apache-2.0 |
9 | oslo.log>=1.12.0 # Apache-2.0 | |
9 | oslo.log>=1.14.0 # Apache-2.0 | |
10 | 10 | oslo.policy>=0.5.0 # Apache-2.0 |
11 | 11 | oslo.serialization>=1.10.0 # Apache-2.0 |
12 | oslo.utils>=2.8.0 # Apache-2.0 | |
12 | oslo.utils>=3.5.0 # Apache-2.0 |
14 | 14 | Programming Language :: Python |
15 | 15 | Programming Language :: Python :: 2 |
16 | 16 | Programming Language :: Python :: 2.7 |
17 | Programming Language :: Python :: 2.6 | |
18 | 17 | Programming Language :: Python :: 3 |
19 | 18 | Programming Language :: Python :: 3.4 |
20 | 19 |
0 | 0 | # The order of packages is significant, because pip processes them in the order |
1 | 1 | # of appearance. Changing the order has an impact on the overall integration |
2 | 2 | # process, which may cause wedges in the gate later. |
3 | hacking<0.11,>=0.10.2 # Apache-2.0 | |
3 | 4 | |
4 | hacking<0.10,>=0.9.2 | |
5 | ||
6 | coverage>=3.6 | |
7 | discover | |
8 | python-barbicanclient>=3.3.0 | |
9 | python-subunit>=0.0.18 | |
10 | sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 | |
5 | coverage>=3.6 # Apache-2.0 | |
6 | discover # BSD | |
7 | python-barbicanclient>=3.3.0 # Apache-2.0 | |
8 | python-subunit>=0.0.18 # Apache-2.0/BSD | |
9 | sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD | |
11 | 10 | oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 |
12 | 11 | oslotest>=1.10.0 # Apache-2.0 |
13 | testrepository>=0.0.18 | |
14 | testscenarios>=0.4 | |
15 | testtools>=1.4.0 | |
12 | testrepository>=0.0.18 # Apache-2.0/BSD | |
13 | testscenarios>=0.4 # Apache-2.0/BSD | |
14 | testtools>=1.4.0 # MIT |
0 | 0 | [tox] |
1 | 1 | minversion = 1.6 |
2 | envlist = py34,py26,py27,pypy,pep8 | |
2 | envlist = py34,py27,pypy,pep8 | |
3 | 3 | skipsdist = True |
4 | 4 | |
5 | 5 | [testenv] |
47 | 47 | # E123, E125 skipped as they are invalid PEP-8. |
48 | 48 | |
49 | 49 | show-source = True |
50 | ignore = E123,E125,H803 | |
50 | ignore = E123,E125 | |
51 | 51 | exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build |