Initial commit of the keystone-kerberos charm
Original authors: Camille Rodriguez Aymen Frikha
This commit is contained in:
commit
bebba096e3
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.tox
|
||||||
|
.stestr
|
||||||
|
*__pycache__*
|
||||||
|
*.pyc
|
||||||
|
build
|
||||||
|
src/tests/bundles/overlays/local-charm-overlay.yaml.j2
|
||||||
|
interfaces
|
||||||
|
layers
|
||||||
|
.idea
|
4
.gitreview
Normal file
4
.gitreview
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[gerrit]
|
||||||
|
host=review.openstack.org
|
||||||
|
port=29418
|
||||||
|
project=openstack/charm-keystone-kerberos.git
|
3
.stestr.conf
Normal file
3
.stestr.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
test_path=./unit_tests
|
||||||
|
top_dir=./
|
6
.travis.yml
Normal file
6
.travis.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
language: python
|
||||||
|
python:
|
||||||
|
- "3.6"
|
||||||
|
install: pip install tox-travis
|
||||||
|
script:
|
||||||
|
- tox -e pep8,py3
|
4
.zuul.yaml
Normal file
4
.zuul.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
- project:
|
||||||
|
templates:
|
||||||
|
- python35-charm-jobs
|
||||||
|
- openstack-python3-train-jobs
|
201
LICENSE
Normal file
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
8
requirements.txt
Normal file
8
requirements.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# This file is managed centrally by release-tools and should not be modified
|
||||||
|
# within individual charm repos. See the 'global' dir contents for available
|
||||||
|
# choices of *requirements.txt files for OpenStack Charms:
|
||||||
|
# https://github.com/openstack-charmers/release-tools
|
||||||
|
#
|
||||||
|
# Build requirements
|
||||||
|
charm-tools>=2.4.4
|
||||||
|
simplejson
|
111
src/README.md
Normal file
111
src/README.md
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
# keystone-kerberos
|
||||||
|
|
||||||
|
This subordinate charm provides a way to authenticate in Openstack for
|
||||||
|
a specific domain with a Kerberos ticket. This provides an additional
|
||||||
|
security layer. An external Kerberos server is necessary.
|
||||||
|
|
||||||
|
The following documentation is useful to understand better the charm
|
||||||
|
implementation:
|
||||||
|
|
||||||
|
* https://www.objectif-libre.com/fr/blog/2018/02/26/kerberos-authentication-for-keystone/
|
||||||
|
* https://jaosorior.dev/2018/keberos-for-keystone-with-mod_auth_gssapi/
|
||||||
|
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
Use this charm with the Keystone and Keystone-LDAP charms:
|
||||||
|
|
||||||
|
juju deploy keystone
|
||||||
|
juju deploy keystone-ldap
|
||||||
|
juju deploy openstack-dashboard
|
||||||
|
juju deploy keystone-kerberos
|
||||||
|
juju add-relation keystone keystone-ldap
|
||||||
|
juju add-relation keystone openstack-dashboard
|
||||||
|
juju add-relation keystone keystone-kerberos
|
||||||
|
|
||||||
|
In a bundle:
|
||||||
|
|
||||||
|
```
|
||||||
|
applications
|
||||||
|
# ...
|
||||||
|
keystone-kerberos:
|
||||||
|
charm: ../../../keystone-kerberos
|
||||||
|
num_units: 0
|
||||||
|
options:
|
||||||
|
kerberos-realm: "PROJECT.SERVERSTACK"
|
||||||
|
kerberos-server: "freeipa.project.serverstack"
|
||||||
|
kerberos-domain: "k8s"
|
||||||
|
resources:
|
||||||
|
keystone_keytab: "/home/ubuntu/keystone.keytab"
|
||||||
|
relations:
|
||||||
|
# ...
|
||||||
|
- - keystone
|
||||||
|
- keystone-kerberos
|
||||||
|
```
|
||||||
|
|
||||||
|
# Prerequisites
|
||||||
|
|
||||||
|
To authenticate against Keystone and Kerberos from a host, the following
|
||||||
|
librairies need to be installed :
|
||||||
|
- sudo apt install krb5-user gcc python-dev libkrb5-dev python-pip
|
||||||
|
- pip install keystoneauth1[kerberos]
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
|
||||||
|
In the Kerberos server, a service must be created for the Keystone Principal.
|
||||||
|
For example, first find the hostname of the keystone server :
|
||||||
|
|
||||||
|
ubuntu@keystone-server$ hostname -f
|
||||||
|
keystone-server.project.serverstack
|
||||||
|
|
||||||
|
Note 1 : make sure that your keystone server can resolve the Kerberos server
|
||||||
|
hostname. If if can't, consider adding an entry to /etc/hosts.
|
||||||
|
|
||||||
|
Then, in the Kerberos server, create the host and service (this example is
|
||||||
|
based on a FreeIPA Kerberos Server):
|
||||||
|
|
||||||
|
ipa host-add keystone-server.project.serverstack --ip-adress=10.0.0.2
|
||||||
|
ipa service-add HTTP/keystone-server.project.serverstack
|
||||||
|
ipa service-add-host HTTP/keystone-server.project.serverstack --hosts=keystone-server.project.serverstack
|
||||||
|
|
||||||
|
Note 2 : If you have multiple keystone servers, you should add each host to
|
||||||
|
the principal with the command
|
||||||
|
|
||||||
|
ipa host-add-principal keystone-server HTTP/<keystone-other-hostname>@PROJECT.SERVERSTACK
|
||||||
|
|
||||||
|
Retrieve the keytab associated with this service:
|
||||||
|
|
||||||
|
ipa-getkeytab -p HTTP/keystone-server.project.serverstack -k keystone.keytab
|
||||||
|
|
||||||
|
This is the keytab needed in the resources of the keystone-kerberos charm. If
|
||||||
|
you retrieved it post-deploy, you can attach it with a command to keystone:
|
||||||
|
|
||||||
|
juju attach-resource keystone-kerberos/0 keystone_keytab=new_keytab.keytab
|
||||||
|
|
||||||
|
# Authentication from a host
|
||||||
|
|
||||||
|
To use the Openstack cli, two steps are required.
|
||||||
|
1) Retrieve a token for an existing user in the Kerberos/LDAP directory:
|
||||||
|
```
|
||||||
|
kinit <username>
|
||||||
|
```
|
||||||
|
2) Source the openstack rc file with the correct information:
|
||||||
|
```
|
||||||
|
cat k8s-user.rc
|
||||||
|
export OS_AUTH_URL=http://kerberos-server.project.serverstack:5000/krb/v3
|
||||||
|
export OS_PROJECT_ID=<projectID>
|
||||||
|
export OS_PROJECT_NAME=<kerberos_domain> # i.e k8s
|
||||||
|
export OS_PROJECT_DOMAIN_ID=<domainID>
|
||||||
|
export OS_REGION_NAME="RegionOne"
|
||||||
|
export OS_INTERFACE=public
|
||||||
|
export OS_IDENTITY_API_VERSION=3
|
||||||
|
export OS_AUTH_TYPE=v3kerberos
|
||||||
|
|
||||||
|
source k8s-user.rc
|
||||||
|
openstack token issue
|
||||||
|
```
|
||||||
|
|
||||||
|
# Bugs
|
||||||
|
Please report bugs on [Launchpad](link missing).
|
||||||
|
|
||||||
|
For general questions please refer to the OpenStack [Charm Guide](https://docs.openstack.org/charm-guide/latest/).
|
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
25
src/config.yaml
Normal file
25
src/config.yaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
options:
|
||||||
|
display-name:
|
||||||
|
type: string
|
||||||
|
default: 'keystone-kerberos'
|
||||||
|
description: Custom name for UI
|
||||||
|
kerberos-realm:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
description: |
|
||||||
|
The domain over which a Kerberos authentication server has the authority
|
||||||
|
to authenticate a user, host or service. It is often the upper case
|
||||||
|
version fo the name of the DNS domain over which is presides,
|
||||||
|
i.e REALM.COM. Must be in caps.
|
||||||
|
kerberos-server:
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
description: |
|
||||||
|
Kerberos server name. Typically, the server name is composed of a name
|
||||||
|
followed by the realm name, i.e, krb5.realm.com
|
||||||
|
kerberos-domain:
|
||||||
|
type: string
|
||||||
|
default: 'k8s'
|
||||||
|
description: |
|
||||||
|
The Openstack domain against which Kerberos authentication should be
|
||||||
|
used.
|
279
src/icon.svg
Normal file
279
src/icon.svg
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="96"
|
||||||
|
height="96"
|
||||||
|
id="svg6517"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48+devel r12274"
|
||||||
|
sodipodi:docname="Juju_charm_icon_template.svg">
|
||||||
|
<defs
|
||||||
|
id="defs6519">
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#Background"
|
||||||
|
id="linearGradient6461"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="0"
|
||||||
|
y1="970.29498"
|
||||||
|
x2="144"
|
||||||
|
y2="970.29498"
|
||||||
|
gradientTransform="matrix(0,-0.66666669,0.6660448,0,-866.25992,731.29077)" />
|
||||||
|
<linearGradient
|
||||||
|
id="Background">
|
||||||
|
<stop
|
||||||
|
id="stop4178"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#b8b8b8;stop-opacity:1" />
|
||||||
|
<stop
|
||||||
|
id="stop4180"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#c9c9c9;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
style="color-interpolation-filters:sRGB;"
|
||||||
|
inkscape:label="Inner Shadow"
|
||||||
|
id="filter1121">
|
||||||
|
<feFlood
|
||||||
|
flood-opacity="0.59999999999999998"
|
||||||
|
flood-color="rgb(0,0,0)"
|
||||||
|
result="flood"
|
||||||
|
id="feFlood1123" />
|
||||||
|
<feComposite
|
||||||
|
in="flood"
|
||||||
|
in2="SourceGraphic"
|
||||||
|
operator="out"
|
||||||
|
result="composite1"
|
||||||
|
id="feComposite1125" />
|
||||||
|
<feGaussianBlur
|
||||||
|
in="composite1"
|
||||||
|
stdDeviation="1"
|
||||||
|
result="blur"
|
||||||
|
id="feGaussianBlur1127" />
|
||||||
|
<feOffset
|
||||||
|
dx="0"
|
||||||
|
dy="2"
|
||||||
|
result="offset"
|
||||||
|
id="feOffset1129" />
|
||||||
|
<feComposite
|
||||||
|
in="offset"
|
||||||
|
in2="SourceGraphic"
|
||||||
|
operator="atop"
|
||||||
|
result="composite2"
|
||||||
|
id="feComposite1131" />
|
||||||
|
</filter>
|
||||||
|
<filter
|
||||||
|
style="color-interpolation-filters:sRGB;"
|
||||||
|
inkscape:label="Drop Shadow"
|
||||||
|
id="filter950">
|
||||||
|
<feFlood
|
||||||
|
flood-opacity="0.25"
|
||||||
|
flood-color="rgb(0,0,0)"
|
||||||
|
result="flood"
|
||||||
|
id="feFlood952" />
|
||||||
|
<feComposite
|
||||||
|
in="flood"
|
||||||
|
in2="SourceGraphic"
|
||||||
|
operator="in"
|
||||||
|
result="composite1"
|
||||||
|
id="feComposite954" />
|
||||||
|
<feGaussianBlur
|
||||||
|
in="composite1"
|
||||||
|
stdDeviation="1"
|
||||||
|
result="blur"
|
||||||
|
id="feGaussianBlur956" />
|
||||||
|
<feOffset
|
||||||
|
dx="0"
|
||||||
|
dy="1"
|
||||||
|
result="offset"
|
||||||
|
id="feOffset958" />
|
||||||
|
<feComposite
|
||||||
|
in="SourceGraphic"
|
||||||
|
in2="offset"
|
||||||
|
operator="over"
|
||||||
|
result="composite2"
|
||||||
|
id="feComposite960" />
|
||||||
|
</filter>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath873">
|
||||||
|
<g
|
||||||
|
transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)"
|
||||||
|
id="g875"
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline">
|
||||||
|
<path
|
||||||
|
style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline"
|
||||||
|
d="m 46.702703,898.22775 50.594594,0 C 138.16216,898.22775 144,904.06497 144,944.92583 l 0,50.73846 c 0,40.86071 -5.83784,46.69791 -46.702703,46.69791 l -50.594594,0 C 5.8378378,1042.3622 0,1036.525 0,995.66429 L 0,944.92583 C 0,904.06497 5.8378378,898.22775 46.702703,898.22775 Z"
|
||||||
|
id="path877"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="sssssssss" />
|
||||||
|
</g>
|
||||||
|
</clipPath>
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="filter891"
|
||||||
|
inkscape:label="Badge Shadow">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="0.71999962"
|
||||||
|
id="feGaussianBlur893" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="4.0745362"
|
||||||
|
inkscape:cx="18.514671"
|
||||||
|
inkscape:cy="49.018169"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1029"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="24"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showborder="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:showpageshadow="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid821" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="16,48"
|
||||||
|
id="guide823" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="64,80"
|
||||||
|
id="guide825" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="80,40"
|
||||||
|
id="guide827" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="64,16"
|
||||||
|
id="guide829" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata6522">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="BACKGROUND"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(268,-635.29076)"
|
||||||
|
style="display:inline">
|
||||||
|
<path
|
||||||
|
style="fill:url(#linearGradient6461);fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)"
|
||||||
|
d="m -268,700.15563 0,-33.72973 c 0,-27.24324 3.88785,-31.13513 31.10302,-31.13513 l 33.79408,0 c 27.21507,0 31.1029,3.89189 31.1029,31.13513 l 0,33.72973 c 0,27.24325 -3.88783,31.13514 -31.1029,31.13514 l -33.79408,0 C -264.11215,731.29077 -268,727.39888 -268,700.15563 Z"
|
||||||
|
id="path6455"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="sssssssss" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer3"
|
||||||
|
inkscape:label="PLACE YOUR PICTOGRAM HERE"
|
||||||
|
style="display:inline" />
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="BADGE"
|
||||||
|
style="display:none"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<g
|
||||||
|
style="display:inline"
|
||||||
|
transform="translate(-340.00001,-581)"
|
||||||
|
id="g4394"
|
||||||
|
clip-path="none">
|
||||||
|
<g
|
||||||
|
id="g855">
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="maskhelper"
|
||||||
|
id="g870"
|
||||||
|
clip-path="url(#clipPath873)"
|
||||||
|
style="opacity:0.6;filter:url(#filter891)">
|
||||||
|
<path
|
||||||
|
transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)"
|
||||||
|
d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z"
|
||||||
|
sodipodi:ry="12"
|
||||||
|
sodipodi:rx="12"
|
||||||
|
sodipodi:cy="552.36218"
|
||||||
|
sodipodi:cx="252"
|
||||||
|
id="path844"
|
||||||
|
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||||
|
sodipodi:type="arc" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g862">
|
||||||
|
<path
|
||||||
|
sodipodi:type="arc"
|
||||||
|
style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||||
|
id="path4398"
|
||||||
|
sodipodi:cx="252"
|
||||||
|
sodipodi:cy="552.36218"
|
||||||
|
sodipodi:rx="12"
|
||||||
|
sodipodi:ry="12"
|
||||||
|
d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z"
|
||||||
|
transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)" />
|
||||||
|
<path
|
||||||
|
transform="matrix(1.25,0,0,1.25,33,-100.45273)"
|
||||||
|
d="m 264,552.36218 a 12,12 0 1 1 -24,0 A 12,12 0 1 1 264,552.36218 Z"
|
||||||
|
sodipodi:ry="12"
|
||||||
|
sodipodi:rx="12"
|
||||||
|
sodipodi:cy="552.36218"
|
||||||
|
sodipodi:cx="252"
|
||||||
|
id="path4400"
|
||||||
|
style="color:#000000;fill:#dd4814;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||||
|
sodipodi:type="arc" />
|
||||||
|
<path
|
||||||
|
sodipodi:type="star"
|
||||||
|
style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||||
|
id="path4459"
|
||||||
|
sodipodi:sides="5"
|
||||||
|
sodipodi:cx="666.19574"
|
||||||
|
sodipodi:cy="589.50385"
|
||||||
|
sodipodi:r1="7.2431178"
|
||||||
|
sodipodi:r2="4.3458705"
|
||||||
|
sodipodi:arg1="1.0471976"
|
||||||
|
sodipodi:arg2="1.6755161"
|
||||||
|
inkscape:flatsided="false"
|
||||||
|
inkscape:rounded="0.1"
|
||||||
|
inkscape:randomized="0"
|
||||||
|
d="m 669.8173,595.77657 c -0.39132,0.22593 -3.62645,-1.90343 -4.07583,-1.95066 -0.44938,-0.0472 -4.05653,1.36297 -4.39232,1.06062 -0.3358,-0.30235 0.68963,-4.03715 0.59569,-4.47913 -0.0939,-0.44198 -2.5498,-3.43681 -2.36602,-3.8496 0.18379,-0.41279 4.05267,-0.59166 4.44398,-0.81759 0.39132,-0.22593 2.48067,-3.48704 2.93005,-3.4398 0.44938,0.0472 1.81505,3.67147 2.15084,3.97382 0.3358,0.30236 4.08294,1.2817 4.17689,1.72369 0.0939,0.44198 -2.9309,2.86076 -3.11469,3.27355 C 669.9821,591.68426 670.20862,595.55064 669.8173,595.77657 Z"
|
||||||
|
transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 9.6 KiB |
6
src/layer.yaml
Normal file
6
src/layer.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
includes: ['layer:openstack', 'interface:keystone-fid-service-provider', 'interface:juju-info']
|
||||||
|
repo: https://github.com/camille-rodriguez/keystone-kerberos.git
|
||||||
|
options:
|
||||||
|
basic:
|
||||||
|
use_venv: True
|
||||||
|
include_system_packages: False
|
0
src/lib/charm/openstack/__init__.py
Normal file
0
src/lib/charm/openstack/__init__.py
Normal file
203
src/lib/charm/openstack/keystone_kerberos.py
Normal file
203
src/lib/charm/openstack/keystone_kerberos.py
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2017 Canonical Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import charmhelpers.core as core
|
||||||
|
import charmhelpers.core.host as ch_host
|
||||||
|
import charmhelpers.core.hookenv as hookenv
|
||||||
|
|
||||||
|
import charmhelpers.contrib.openstack.templating as os_templating
|
||||||
|
import charmhelpers.contrib.openstack.utils as os_utils
|
||||||
|
|
||||||
|
import charms_openstack.charm
|
||||||
|
import charms_openstack.adapters
|
||||||
|
# release detection is done via keystone package given that
|
||||||
|
# openstack-origin is not present in the subordinate charm
|
||||||
|
# see https://github.com/juju/charm-helpers/issues/83
|
||||||
|
import charmhelpers.core.unitdata as unitdata
|
||||||
|
from charms_openstack.charm.core import (
|
||||||
|
register_os_release_selector
|
||||||
|
)
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
OPENSTACK_RELEASE_KEY = 'charmers.openstack-release-version'
|
||||||
|
APACHE_CONF_TEMPLATE = "apache-kerberos.conf"
|
||||||
|
APACHE_LOCATION = '/etc/apache2/kerberos'
|
||||||
|
KERBEROS_CONF_TEMPLATE = "krb5.conf"
|
||||||
|
KEYTAB_DESTINATION_PATH = "/etc/keystone.keytab"
|
||||||
|
|
||||||
|
|
||||||
|
@register_os_release_selector
|
||||||
|
def select_release():
|
||||||
|
"""Determine the release based on the keystone package version.
|
||||||
|
|
||||||
|
Note that this function caches the release after the first install so
|
||||||
|
that it doesn't need to keep going and getting it from the package
|
||||||
|
information.
|
||||||
|
"""
|
||||||
|
release_version = unitdata.kv().get(OPENSTACK_RELEASE_KEY, None)
|
||||||
|
if release_version is None:
|
||||||
|
release_version = os_utils.os_release('keystone')
|
||||||
|
unitdata.kv().set(OPENSTACK_RELEASE_KEY, release_version)
|
||||||
|
return release_version
|
||||||
|
|
||||||
|
|
||||||
|
class KeystoneKerberosConfigurationAdapter(
|
||||||
|
charms_openstack.adapters.ConfigurationAdapter):
|
||||||
|
|
||||||
|
def __init__(self, charm_instance=None):
|
||||||
|
super().__init__(charm_instance=charm_instance)
|
||||||
|
self._keytab_path = None
|
||||||
|
self._protocol_name = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def keytab_path(self):
|
||||||
|
"""Path for they keytab file"""
|
||||||
|
keytab_file = hookenv.resource_get('keystone_keytab')
|
||||||
|
if keytab_file:
|
||||||
|
shutil.copy(keytab_file, KEYTAB_DESTINATION_PATH)
|
||||||
|
self._keytab_path = keytab_file
|
||||||
|
return self._keytab_path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def protocol_name(self):
|
||||||
|
"""Protocol name to be used in the auth methods via
|
||||||
|
fid-service-provider interface
|
||||||
|
|
||||||
|
:returns: string: containing the protocol name
|
||||||
|
"""
|
||||||
|
self._protocol_name = 'kerberos'
|
||||||
|
return self._protocol_name
|
||||||
|
|
||||||
|
|
||||||
|
class KeystoneKerberosCharm(charms_openstack.charm.OpenStackCharm):
|
||||||
|
|
||||||
|
# Internal name of charm
|
||||||
|
|
||||||
|
service_name = name = 'keystone-kerberos'
|
||||||
|
|
||||||
|
# Package to derive application version from
|
||||||
|
|
||||||
|
version_package = 'keystone'
|
||||||
|
|
||||||
|
# First release supported
|
||||||
|
|
||||||
|
release = 'queens'
|
||||||
|
|
||||||
|
release_pkg = 'keystone-common'
|
||||||
|
|
||||||
|
# Required relations
|
||||||
|
|
||||||
|
required_relations = [
|
||||||
|
'keystone-fid-service-provider']
|
||||||
|
|
||||||
|
# List of packages to install for this charm
|
||||||
|
|
||||||
|
packages = ['libapache2-mod-auth-kerb']
|
||||||
|
|
||||||
|
configuration_class = KeystoneKerberosConfigurationAdapter
|
||||||
|
|
||||||
|
restart_map = {
|
||||||
|
APACHE_CONF_TEMPLATE: [],
|
||||||
|
KERBEROS_CONF_TEMPLATE: [],
|
||||||
|
KEYTAB_DESTINATION_PATH: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kerberos_realm(self):
|
||||||
|
"""Realm name for the running application
|
||||||
|
|
||||||
|
:returns: string: containing the realm name for the application
|
||||||
|
"""
|
||||||
|
return hookenv.config('kerberos-realm')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kerberos_server(self):
|
||||||
|
"""Server name for the running application
|
||||||
|
|
||||||
|
:returns: string: containing the server name for the application
|
||||||
|
"""
|
||||||
|
return hookenv.config('kerberos-server')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kerberos_domain(self):
|
||||||
|
"""Server name for the running application
|
||||||
|
|
||||||
|
:returns: string: containing the server name for the application
|
||||||
|
"""
|
||||||
|
return hookenv.config('kerberos-domain')
|
||||||
|
|
||||||
|
def configuration_complete(self):
|
||||||
|
"""Determine whether sufficient configuration has been provided
|
||||||
|
to configure keystone for use with a Kerberos server
|
||||||
|
|
||||||
|
:returns: boolean indicating whether configuration is complete
|
||||||
|
"""
|
||||||
|
required_config = {
|
||||||
|
'kerberos_realm': self.options.kerberos_realm,
|
||||||
|
'kerberos_server': self.options.kerberos_server,
|
||||||
|
'kerberos_domain': self.options.kerberos_domain,
|
||||||
|
'keytab_path': self.options.keytab_path,
|
||||||
|
}
|
||||||
|
return all(required_config.values())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kerb_conf_path(self):
|
||||||
|
return '/kerberos'
|
||||||
|
|
||||||
|
def assess_status(self):
|
||||||
|
"""Determine the current application status for the charm"""
|
||||||
|
if not self.configuration_complete():
|
||||||
|
hookenv.status_set('blocked',
|
||||||
|
'Kerberos configuration incomplete')
|
||||||
|
elif os_utils.is_unit_upgrading_set():
|
||||||
|
hookenv.status_set('blocked',
|
||||||
|
'Ready for do-release-upgrade and reboot. '
|
||||||
|
'Set complete when finished.')
|
||||||
|
else:
|
||||||
|
hookenv.status_set('active',
|
||||||
|
'Unit is ready')
|
||||||
|
|
||||||
|
def render_config(self, *args):
|
||||||
|
"""
|
||||||
|
Render Kerberos configuration file and Apache configuration to be used
|
||||||
|
by Keystone.
|
||||||
|
"""
|
||||||
|
# ensure that a directory we need is there
|
||||||
|
ch_host.mkdir(APACHE_LOCATION)
|
||||||
|
|
||||||
|
self.render_configs(self.string_templates.keys())
|
||||||
|
|
||||||
|
core.templating.render(
|
||||||
|
source=APACHE_CONF_TEMPLATE,
|
||||||
|
template_loader=os_templating.get_loader(
|
||||||
|
'templates/', self.release),
|
||||||
|
target='{}/{}'.format(APACHE_LOCATION, APACHE_CONF_TEMPLATE),
|
||||||
|
context=self.adapters_class(args, charm_instance=self),
|
||||||
|
)
|
||||||
|
|
||||||
|
core.templating.render(
|
||||||
|
source=KERBEROS_CONF_TEMPLATE,
|
||||||
|
template_loader=os_templating.get_loader(
|
||||||
|
'templates/', self.release),
|
||||||
|
target="/etc/krb5.conf",
|
||||||
|
context=self.adapters_class(args, charm_instance=self),
|
||||||
|
)
|
||||||
|
|
||||||
|
def remove_config(self):
|
||||||
|
for f in self.restart_map.keys():
|
||||||
|
if os.path.exists(f):
|
||||||
|
os.unlink(f)
|
28
src/metadata.yaml
Normal file
28
src/metadata.yaml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: keystone-kerberos
|
||||||
|
summary: Keystone backend for kerberos authentication
|
||||||
|
maintainer: OpenStack Charmers <openstack-charmers@lists.ubuntu.com>
|
||||||
|
description: |
|
||||||
|
This charm supports the use of Kerberos as a security mechanism
|
||||||
|
for authentication through keystone.
|
||||||
|
tags:
|
||||||
|
- openstack
|
||||||
|
- identity
|
||||||
|
- kerberos
|
||||||
|
- ldap
|
||||||
|
series:
|
||||||
|
- bionic
|
||||||
|
- eoan
|
||||||
|
subordinate: true
|
||||||
|
provides:
|
||||||
|
keystone-fid-service-provider:
|
||||||
|
interface: keystone-fid-service-provider
|
||||||
|
scope: container
|
||||||
|
requires:
|
||||||
|
container:
|
||||||
|
interface: juju-info
|
||||||
|
scope: container
|
||||||
|
resources:
|
||||||
|
keystone_keytab:
|
||||||
|
type: file
|
||||||
|
filename: keystone.keytab
|
||||||
|
description: Path to the kerberos keytab for keystone service
|
61
src/reactive/keystone_kerberos_handlers.py
Normal file
61
src/reactive/keystone_kerberos_handlers.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#
|
||||||
|
# Copyright 2020 Canonical Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import charms_openstack.bus
|
||||||
|
charms_openstack.bus.discover()
|
||||||
|
|
||||||
|
|
||||||
|
import charms_openstack.charm as charm
|
||||||
|
import charms.reactive as reactive
|
||||||
|
|
||||||
|
charm.use_defaults(
|
||||||
|
'charm.installed',
|
||||||
|
'update-status',
|
||||||
|
'upgrade-charm')
|
||||||
|
|
||||||
|
|
||||||
|
@reactive.when_not('keystone-fid-service-provider.connected')
|
||||||
|
def keystone_departed():
|
||||||
|
"""
|
||||||
|
Service restart should be handled on the keystone side
|
||||||
|
in this case.
|
||||||
|
"""
|
||||||
|
with charm.provide_charm_instance() as charm_instance:
|
||||||
|
charm_instance.remove_config()
|
||||||
|
|
||||||
|
|
||||||
|
@reactive.when('keystone-fid-service-provider.connected')
|
||||||
|
def publish_sp_fid(fid_sp):
|
||||||
|
with charm.provide_charm_instance() as charm_instance:
|
||||||
|
fid_sp.publish(charm_instance.options.protocol_name,
|
||||||
|
charm_instance.options.kerberos_server)
|
||||||
|
|
||||||
|
|
||||||
|
@reactive.when('keystone-fid-service-provider.available')
|
||||||
|
def render_config(fid_sp):
|
||||||
|
with charm.provide_charm_instance() as charm_instance:
|
||||||
|
if charm_instance.configuration_complete():
|
||||||
|
charm_instance.render_config(fid_sp)
|
||||||
|
# Trigger keystone restart. The relation is container-scoped
|
||||||
|
# so a per-unit db of a remote unit will only contain a nonce
|
||||||
|
# of a single subordinate
|
||||||
|
if reactive.any_file_changed(charm_instance.restart_map.keys()):
|
||||||
|
fid_sp.request_restart()
|
||||||
|
|
||||||
|
|
||||||
|
@reactive.when_not('always.run')
|
||||||
|
def assess_status():
|
||||||
|
with charm.provide_charm_instance() as charm_instance:
|
||||||
|
charm_instance.assess_status()
|
15
src/templates/apache-kerberos.conf
Normal file
15
src/templates/apache-kerberos.conf
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<Location "/krb/v3/auth/tokens">
|
||||||
|
LogLevel trace8
|
||||||
|
AuthType Kerberos
|
||||||
|
AuthName "Kerberos Login"
|
||||||
|
KrbMethodNegotiate On
|
||||||
|
KrbMethodK5Passwd Off
|
||||||
|
KrbServiceName HTTP
|
||||||
|
KrbAuthRealms {{ options.kerberos_realm }}
|
||||||
|
Krb5KeyTab {{ options.keytab_path }}
|
||||||
|
KrbVerifyKDC Off
|
||||||
|
KrbLocalUserMapping On
|
||||||
|
KrbAuthoritative On
|
||||||
|
Require valid-user
|
||||||
|
SetEnv REMOTE_DOMAIN {{ options.kerberos_domain }}
|
||||||
|
</Location>
|
21
src/templates/krb5.conf
Normal file
21
src/templates/krb5.conf
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[libdefaults]
|
||||||
|
default_realm = {{ options.kerberos_realm }}
|
||||||
|
|
||||||
|
# The following krb5.conf variables are only for MIT Kerberos.
|
||||||
|
kdc_timesync = 1
|
||||||
|
ccache_type = 4
|
||||||
|
forwardable = true
|
||||||
|
proxiable = true
|
||||||
|
|
||||||
|
|
||||||
|
fcc-mit-ticketflags = true
|
||||||
|
|
||||||
|
[realms]
|
||||||
|
{{ options.kerberos_realm }} = {
|
||||||
|
kdc = {{ options.kerberos_server }}
|
||||||
|
admin_server = {{ options.kerberos_server }}
|
||||||
|
}
|
||||||
|
|
||||||
|
[domain_realm]
|
||||||
|
.{% filter lower %}{{ options.kerberos_realm }}{% endfilter %} = {{ options.kerberos_realm }}
|
||||||
|
{% filter lower %}{{ options.kerberos_realm }}{% endfilter %} = {{ options.kerberos_realm }}
|
8
src/test-requirements.txt
Normal file
8
src/test-requirements.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# This file is managed centrally by release-tools and should not be modified
|
||||||
|
# within individual charm repos. See the 'global' dir contents for available
|
||||||
|
# choices of *requirements.txt files for OpenStack Charms:
|
||||||
|
# https://github.com/openstack-charmers/release-tools
|
||||||
|
#
|
||||||
|
# Functional Test Requirements (let Zaza's dependencies solve all dependencies here!)
|
||||||
|
git+https://github.com/openstack-charmers/zaza.git#egg=zaza
|
||||||
|
git+https://github.com/openstack-charmers/zaza-openstack-tests.git#egg=zaza.openstack
|
50
src/tox.ini
Normal file
50
src/tox.ini
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Source charm (with zaza): ./src/tox.ini
|
||||||
|
# This file is managed centrally by release-tools and should not be modified
|
||||||
|
# within individual charm repos. See the 'global' dir contents for available
|
||||||
|
# choices of tox.ini for OpenStack Charms:
|
||||||
|
# https://github.com/openstack-charmers/release-tools
|
||||||
|
|
||||||
|
[tox]
|
||||||
|
envlist = pep8
|
||||||
|
skipsdist = True
|
||||||
|
# NOTE: Avoid build/test env pollution by not enabling sitepackages.
|
||||||
|
sitepackages = False
|
||||||
|
# NOTE: Avoid false positives by not skipping missing interpreters.
|
||||||
|
skip_missing_interpreters = False
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
setenv = VIRTUAL_ENV={envdir}
|
||||||
|
PYTHONHASHSEED=0
|
||||||
|
whitelist_externals = juju
|
||||||
|
passenv = HOME TERM CS_* OS_* TEST_*
|
||||||
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
|
install_command =
|
||||||
|
pip install {opts} {packages}
|
||||||
|
|
||||||
|
[testenv:pep8]
|
||||||
|
basepython = python3
|
||||||
|
deps=charm-tools
|
||||||
|
commands = charm-proof
|
||||||
|
|
||||||
|
[testenv:func-noop]
|
||||||
|
basepython = python3
|
||||||
|
commands =
|
||||||
|
functest-run-suite --help
|
||||||
|
|
||||||
|
[testenv:func]
|
||||||
|
basepython = python3
|
||||||
|
commands =
|
||||||
|
functest-run-suite --keep-model
|
||||||
|
|
||||||
|
[testenv:func-smoke]
|
||||||
|
basepython = python3
|
||||||
|
commands =
|
||||||
|
functest-run-suite --keep-model --smoke
|
||||||
|
|
||||||
|
[testenv:func-target]
|
||||||
|
basepython = python3
|
||||||
|
commands =
|
||||||
|
functest-run-suite --keep-model --bundle {posargs}
|
||||||
|
|
||||||
|
[testenv:venv]
|
||||||
|
commands = {posargs}
|
13
test-requirements.txt
Normal file
13
test-requirements.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# This file is managed centrally. If you find the need to modify this as a
|
||||||
|
# one-off, please don't. Intead, consult #openstack-charms and ask about
|
||||||
|
# requirements management in charms via bot-control. Thank you.
|
||||||
|
#
|
||||||
|
# Lint and unit test requirements
|
||||||
|
flake8>=2.2.4,<=2.4.1
|
||||||
|
stestr>=2.2.0
|
||||||
|
requests>=2.18.4
|
||||||
|
charms.reactive
|
||||||
|
mock>=1.2
|
||||||
|
nose>=1.3.7
|
||||||
|
coverage>=3.6
|
||||||
|
git+https://github.com/openstack/charms.openstack.git#egg=charms.openstack
|
92
tox.ini
Normal file
92
tox.ini
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# Source charm: ./tox.ini
|
||||||
|
# This file is managed centrally by release-tools and should not be modified
|
||||||
|
# within individual charm repos. See the 'global' dir contents for available
|
||||||
|
# choices of tox.ini for OpenStack Charms:
|
||||||
|
# https://github.com/openstack-charmers/release-tools
|
||||||
|
|
||||||
|
[tox]
|
||||||
|
skipsdist = True
|
||||||
|
envlist = pep8,py3
|
||||||
|
# NOTE: Avoid build/test env pollution by not enabling sitepackages.
|
||||||
|
sitepackages = False
|
||||||
|
# NOTE: Avoid false positives by not skipping missing interpreters.
|
||||||
|
skip_missing_interpreters = False
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
setenv = VIRTUAL_ENV={envdir}
|
||||||
|
PYTHONHASHSEED=0
|
||||||
|
TERM=linux
|
||||||
|
LAYER_PATH={toxinidir}/layers
|
||||||
|
INTERFACE_PATH={toxinidir}/interfaces
|
||||||
|
JUJU_REPOSITORY={toxinidir}/build
|
||||||
|
passenv = http_proxy https_proxy INTERFACE_PATH LAYER_PATH JUJU_REPOSITORY
|
||||||
|
install_command =
|
||||||
|
pip install {opts} {packages}
|
||||||
|
deps =
|
||||||
|
-r{toxinidir}/requirements.txt
|
||||||
|
|
||||||
|
[testenv:build]
|
||||||
|
basepython = python3
|
||||||
|
commands =
|
||||||
|
charm-build --log-level DEBUG -o {toxinidir}/build src {posargs}
|
||||||
|
|
||||||
|
[testenv:py3]
|
||||||
|
basepython = python3
|
||||||
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
|
commands = stestr run --slowest {posargs}
|
||||||
|
|
||||||
|
[testenv:py35]
|
||||||
|
basepython = python3.5
|
||||||
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
|
commands = stestr run --slowest {posargs}
|
||||||
|
|
||||||
|
[testenv:py36]
|
||||||
|
basepython = python3.6
|
||||||
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
|
commands = stestr run --slowest {posargs}
|
||||||
|
|
||||||
|
[testenv:py37]
|
||||||
|
basepython = python3.7
|
||||||
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
|
commands = stestr run --slowest {posargs}
|
||||||
|
|
||||||
|
[testenv:pep8]
|
||||||
|
basepython = python3
|
||||||
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
|
commands = flake8 {posargs} src unit_tests
|
||||||
|
|
||||||
|
[testenv:cover]
|
||||||
|
# Technique based heavily upon
|
||||||
|
# https://github.com/openstack/nova/blob/master/tox.ini
|
||||||
|
basepython = python3
|
||||||
|
deps = -r{toxinidir}/requirements.txt
|
||||||
|
-r{toxinidir}/test-requirements.txt
|
||||||
|
setenv =
|
||||||
|
{[testenv]setenv}
|
||||||
|
PYTHON=coverage run
|
||||||
|
commands =
|
||||||
|
coverage erase
|
||||||
|
stestr run --slowest {posargs}
|
||||||
|
coverage combine
|
||||||
|
coverage html -d cover
|
||||||
|
coverage xml -o cover/coverage.xml
|
||||||
|
coverage report
|
||||||
|
|
||||||
|
[coverage:run]
|
||||||
|
branch = True
|
||||||
|
concurrency = multiprocessing
|
||||||
|
parallel = True
|
||||||
|
source =
|
||||||
|
.
|
||||||
|
omit =
|
||||||
|
.tox/*
|
||||||
|
*/charmhelpers/*
|
||||||
|
unit_tests/*
|
||||||
|
|
||||||
|
[testenv:venv]
|
||||||
|
basepython = python3
|
||||||
|
commands = {posargs}
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
# E402 ignore necessary for path append before sys module import in actions
|
||||||
|
ignore = E402,W504
|
33
unit_tests/__init__.py
Normal file
33
unit_tests/__init__.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Copyright 2019 Canonical Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append('src')
|
||||||
|
sys.path.append('src/lib')
|
||||||
|
sys.path.append('src/actions')
|
||||||
|
|
||||||
|
# Mock out charmhelpers so that we can test without it.
|
||||||
|
# NOTE: The bellow mocks are to avoid side effects at import time.
|
||||||
|
# Any module that requires testing must be re-mocked before usage
|
||||||
|
# in a unit test.
|
||||||
|
import charms_openstack.test_mocks # noqa
|
||||||
|
charms_openstack.test_mocks.mock_charmhelpers()
|
||||||
|
|
||||||
|
import mock
|
||||||
|
import charms
|
||||||
|
keystoneauth1 = mock.MagicMock()
|
||||||
|
sys.modules['keystoneauth1'] = keystoneauth1
|
||||||
|
charms.leadership = mock.MagicMock()
|
||||||
|
sys.modules['charms.leadership'] = charms.leadership
|
118
unit_tests/test_keystone_kerberos_handlers.py
Normal file
118
unit_tests/test_keystone_kerberos_handlers.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# Copyright 2019 Canonical Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
import charm.openstack.keystone_kerberos as keystone_kerberos
|
||||||
|
import reactive.keystone_kerberos_handlers as handlers
|
||||||
|
|
||||||
|
import charms_openstack.test_utils as test_utils
|
||||||
|
|
||||||
|
|
||||||
|
class TestRegisteredHooks(test_utils.TestRegisteredHooks):
|
||||||
|
|
||||||
|
def test_hooks(self):
|
||||||
|
defaults = [
|
||||||
|
'charm.installed',
|
||||||
|
'update-status']
|
||||||
|
hook_set = {
|
||||||
|
'hook': {
|
||||||
|
'default_upgrade_charm': ('upgrade-charm',),
|
||||||
|
},
|
||||||
|
'when': {
|
||||||
|
'publish_sp_fid': (
|
||||||
|
'keystone-fid-service-provider.connected',),
|
||||||
|
'render_config': (
|
||||||
|
'keystone-fid-service-provider.available',),
|
||||||
|
},
|
||||||
|
'when_not': {
|
||||||
|
'keystone_departed': (
|
||||||
|
'keystone-fid-service-provider.connected',),
|
||||||
|
'assess_status': ('always.run',),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
# test that the hooks were registered via the
|
||||||
|
# reactive.keystone_kerberos_handlers
|
||||||
|
self.registered_hooks_test_helper(handlers, hook_set, defaults)
|
||||||
|
|
||||||
|
|
||||||
|
class TestKeystoneKerberosHandlers(test_utils.PatchHelper):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.patch_release(
|
||||||
|
keystone_kerberos.KeystoneKerberosCharm.release)
|
||||||
|
self.keystone_kerberos_charm = mock.MagicMock()
|
||||||
|
self.patch_object(handlers.charm, 'provide_charm_instance',
|
||||||
|
new=mock.MagicMock())
|
||||||
|
self.provide_charm_instance().__enter__.return_value = (
|
||||||
|
self.keystone_kerberos_charm)
|
||||||
|
self.provide_charm_instance().__exit__.return_value = None
|
||||||
|
|
||||||
|
self.patch_object(handlers.reactive, 'any_file_changed',
|
||||||
|
new=mock.MagicMock())
|
||||||
|
|
||||||
|
self.endpoint = mock.MagicMock()
|
||||||
|
|
||||||
|
self.protocol_name = "kerberos"
|
||||||
|
self.kerberos_realm = "project.serverstack"
|
||||||
|
self.kerberos_server = "freeipa.project.serverstack"
|
||||||
|
self.kerberos_domain = "k8s"
|
||||||
|
self.keystone_kerberos_charm.options.protocol_name = (
|
||||||
|
self.protocol_name)
|
||||||
|
self.keystone_kerberos_charm.options.kerberos_realm = (
|
||||||
|
self.kerberos_realm)
|
||||||
|
self.keystone_kerberos_charm.options.kerberos_server = (
|
||||||
|
self.kerberos_server)
|
||||||
|
self.keystone_kerberos_charm.options.kerberos_domain = (
|
||||||
|
self.kerberos_domain)
|
||||||
|
|
||||||
|
self.all_joined_units = []
|
||||||
|
for i in range(0, 2):
|
||||||
|
unit = mock.MagicMock()
|
||||||
|
unit.name = "keystone-{}".format(i)
|
||||||
|
unit.received = {"hostname": unit.name}
|
||||||
|
self.all_joined_units.append(unit)
|
||||||
|
|
||||||
|
def test_keystone_departed(self):
|
||||||
|
handlers.keystone_departed()
|
||||||
|
self.keystone_kerberos_charm.remove_config.assert_called_once_with()
|
||||||
|
|
||||||
|
def test_publish_sp_fid(self):
|
||||||
|
handlers.publish_sp_fid(self.endpoint)
|
||||||
|
self.endpoint.publish.assert_called_once_with(
|
||||||
|
self.protocol_name, self.kerberos_server)
|
||||||
|
|
||||||
|
def test_render_config(self):
|
||||||
|
# No restart
|
||||||
|
self.any_file_changed.return_value = False
|
||||||
|
(self.keystone_kerberos_charm
|
||||||
|
.configuration_complete.return_value) = True
|
||||||
|
|
||||||
|
handlers.render_config(self.endpoint)
|
||||||
|
self.keystone_kerberos_charm.render_config.assert_called_once_with(
|
||||||
|
self.endpoint)
|
||||||
|
self.endpoint.request_restart.assert_not_called()
|
||||||
|
|
||||||
|
# Restart
|
||||||
|
self.any_file_changed.return_value = True
|
||||||
|
handlers.render_config(self.endpoint)
|
||||||
|
self.endpoint.request_restart.assert_called_once_with()
|
||||||
|
|
||||||
|
def test_assess_status(self):
|
||||||
|
handlers.assess_status()
|
||||||
|
self.keystone_kerberos_charm.assess_status.assert_called_once_with()
|
145
unit_tests/test_lib_charm_openstack_keystone_kerberos.py
Normal file
145
unit_tests/test_lib_charm_openstack_keystone_kerberos.py
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
# Copyright 2019 Canonical Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
import charms_openstack.test_utils as test_utils
|
||||||
|
|
||||||
|
import charm.openstack.keystone_kerberos as keystone_kerberos
|
||||||
|
|
||||||
|
|
||||||
|
def FakeConfig(init_dict):
|
||||||
|
|
||||||
|
def _config(key=None):
|
||||||
|
return init_dict[key] if key else init_dict
|
||||||
|
|
||||||
|
return _config
|
||||||
|
|
||||||
|
|
||||||
|
def FakeResourceGet(init_dict):
|
||||||
|
|
||||||
|
def _config(key=None):
|
||||||
|
return init_dict[key] if key else init_dict
|
||||||
|
|
||||||
|
return _config
|
||||||
|
|
||||||
|
|
||||||
|
class Helper(test_utils.PatchHelper):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.patch_release(
|
||||||
|
keystone_kerberos.KeystoneKerberosCharm.release)
|
||||||
|
|
||||||
|
self.endpoint = mock.MagicMock()
|
||||||
|
|
||||||
|
self.kerberos_realm = "project.serverstack"
|
||||||
|
self.kerberos_server = "freeipa.project.serverstack"
|
||||||
|
self.kerberos_domain = "k8s"
|
||||||
|
self.test_config = {
|
||||||
|
"kerberos-realm": self.kerberos_realm,
|
||||||
|
"kerberos-server": self.kerberos_server,
|
||||||
|
"kerberos-domain": self.kerberos_domain,
|
||||||
|
}
|
||||||
|
self.resources = {
|
||||||
|
"keystone_keytab": "/path/to/keystone.keytab",
|
||||||
|
}
|
||||||
|
self.patch_object(keystone_kerberos.hookenv, 'config',
|
||||||
|
side_effect=FakeConfig(self.test_config))
|
||||||
|
self.patch_object(keystone_kerberos.hookenv, 'resource_get',
|
||||||
|
side_effect=FakeResourceGet(self.resources))
|
||||||
|
self.patch_object(
|
||||||
|
keystone_kerberos.hookenv, 'application_version_set')
|
||||||
|
self.patch_object(keystone_kerberos.hookenv, 'status_set')
|
||||||
|
self.patch_object(keystone_kerberos.ch_host, 'mkdir')
|
||||||
|
self.patch_object(keystone_kerberos.core.templating, 'render')
|
||||||
|
|
||||||
|
self.template_loader = mock.MagicMock()
|
||||||
|
self.patch_object(keystone_kerberos.os_templating, 'get_loader',
|
||||||
|
return_value=self.template_loader)
|
||||||
|
self.patch_object(
|
||||||
|
keystone_kerberos.KeystoneKerberosCharm,
|
||||||
|
'application_version',
|
||||||
|
return_value="1.0.0")
|
||||||
|
|
||||||
|
self.patch_object(
|
||||||
|
keystone_kerberos.KeystoneKerberosCharm, 'render_configs')
|
||||||
|
self.patch_object(keystone_kerberos, 'os')
|
||||||
|
self.patch_object(keystone_kerberos, 'shutil')
|
||||||
|
|
||||||
|
self.patch(
|
||||||
|
"builtins.open", new_callable=mock.mock_open(), name="open")
|
||||||
|
self.file = mock.MagicMock()
|
||||||
|
self.fileobj = mock.MagicMock()
|
||||||
|
self.fileobj.__enter__.return_value = self.file
|
||||||
|
self.open.return_value = self.fileobj
|
||||||
|
|
||||||
|
|
||||||
|
class TestKeystoneKerberosConfigurationAdapter(Helper):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.protocol_name = "kerberos"
|
||||||
|
|
||||||
|
def test_keytab_path(self):
|
||||||
|
self.os.path.exists.return_value = True
|
||||||
|
kkca = keystone_kerberos.KeystoneKerberosConfigurationAdapter()
|
||||||
|
self.assertEqual(
|
||||||
|
kkca.keytab_path, self.resources['keystone_keytab'])
|
||||||
|
|
||||||
|
def test_protocol_name(self):
|
||||||
|
kkca = keystone_kerberos.KeystoneKerberosConfigurationAdapter()
|
||||||
|
self.assertEqual(
|
||||||
|
kkca.protocol_name, self.protocol_name)
|
||||||
|
|
||||||
|
|
||||||
|
class TestKeystoneKerberosCharm(Helper):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.patch_object(
|
||||||
|
keystone_kerberos.KeystoneKerberosConfigurationAdapter,
|
||||||
|
'keytab_path')
|
||||||
|
self.keytab_path.return_value = self.resources["keystone_keytab"]
|
||||||
|
self.keytab_path.__bool__.return_value = True
|
||||||
|
|
||||||
|
def test_configuration_complete(self):
|
||||||
|
kk = keystone_kerberos.KeystoneKerberosCharm()
|
||||||
|
self.assertTrue(kk.configuration_complete())
|
||||||
|
|
||||||
|
# One option not ready
|
||||||
|
self.keytab_path.__bool__.return_value = False
|
||||||
|
self.assertFalse(kk.configuration_complete())
|
||||||
|
|
||||||
|
def test_custom_assess_status_check(self):
|
||||||
|
kk = keystone_kerberos.KeystoneKerberosCharm()
|
||||||
|
self.assertEqual(
|
||||||
|
kk.custom_assess_status_check(),
|
||||||
|
(None, None))
|
||||||
|
|
||||||
|
def test_render_config(self):
|
||||||
|
kk = keystone_kerberos.KeystoneKerberosCharm()
|
||||||
|
kk.render_config()
|
||||||
|
self.assertEqual(self.render_configs.call_count, 1)
|
||||||
|
self.assertEqual(self.render.call_count, 2)
|
||||||
|
|
||||||
|
def test_remove_config(self):
|
||||||
|
self.os.path.exists.return_value = True
|
||||||
|
kk = keystone_kerberos.KeystoneKerberosCharm()
|
||||||
|
kk.remove_config()
|
||||||
|
self.assertEqual(self.os.path.exists.call_count, 3)
|
||||||
|
self.assertEqual(self.os.unlink.call_count, 3)
|
Loading…
Reference in New Issue
Block a user