diff options
| author | Christian Heimes <christian@python.org> | 2015-10-15 15:27:23 +0200 |
|---|---|---|
| committer | Christian Heimes <christian@python.org> | 2015-10-15 15:27:23 +0200 |
| commit | 5be736d996f8c6cc85c4d6e859deeea7f7088698 (patch) | |
| tree | 9a7ccbbfa609b9f150c69048dfb402aee672a448 | |
| download | custodia_pwmgr-5be736d996f8c6cc85c4d6e859deeea7f7088698.tar.gz custodia_pwmgr-5be736d996f8c6cc85c4d6e859deeea7f7088698.tar.xz custodia_pwmgr-5be736d996f8c6cc85c4d6e859deeea7f7088698.zip | |
Initial commit of Custodia client API example
| -rw-r--r-- | .dockerignore | 5 | ||||
| -rw-r--r-- | .gitignore | 6 | ||||
| -rw-r--r-- | Dockerfile | 15 | ||||
| -rw-r--r-- | README.txt | 2 | ||||
| -rwxr-xr-x | custodia_pwmgr/custodia_pwmgr.py | 126 | ||||
| -rw-r--r-- | custodia_pwmgr/static/style.css | 19 | ||||
| -rw-r--r-- | custodia_pwmgr/templates/canvas.html | 11 | ||||
| -rw-r--r-- | custodia_pwmgr/templates/index.html | 28 | ||||
| -rw-r--r-- | kubernetes/custodia-pwmgr-rc.yaml | 35 | ||||
| -rw-r--r-- | kubernetes/custodia-pwmgr-service.yaml | 14 | ||||
| -rw-r--r-- | requirements.txt | 5 | ||||
| -rwxr-xr-x | run.sh | 7 |
12 files changed, 273 insertions, 0 deletions
diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0bdbbbf --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +*.pyc +.*swp +__pycache__ + +kubernetes diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e21be1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.pyc +.*swp +__pycache__ + +custodia + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..af9f467 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM fedora +MAINTAINER Christian Heimes + +RUN dnf -y update && dnf clean all +RUN dnf -y install dnf-plugins-core python python-flask python-requests && \ + dnf clean all +RUN dnf -y copr enable simo/jwcrypto && \ + dnf -y install python-jwcrypto python-cryptography && \ + dnf clean all + +ADD . /custodia_pwmgr + +EXPOSE 5000 + +CMD ["/custodia_pwmgr/run.sh"] diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..05c4f2f --- /dev/null +++ b/README.txt @@ -0,0 +1,2 @@ +Custodia client API example + diff --git a/custodia_pwmgr/custodia_pwmgr.py b/custodia_pwmgr/custodia_pwmgr.py new file mode 100755 index 0000000..02f8f9b --- /dev/null +++ b/custodia_pwmgr/custodia_pwmgr.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python2.7 +# +# Authors: +# Christian Heimes <cheimes@redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2015 Red Hat, Inc. +# All rights reserved. +"""Custodia client API example +""" + +import os +import stat +import sys +from urllib import quote + +from flask import Flask, flash, render_template, redirect, request, url_for +from custodia.client import CustodiaClient +from requests.exceptions import HTTPError + +# get Unix socket from env +CUSTODIA_SOCKET = os.environ.get('CUSTODIA_SOCKET') +if CUSTODIA_SOCKET is None: + sys.exit('Please set CUSTODIA_SOCKET env var') +s = os.stat(CUSTODIA_SOCKET) +if not stat.S_ISSOCK(s.st_mode): + sys.exit('%s is not a socket' % CUSTODIA_SOCKET) +del s + + +app = Flask(__name__) +app.config.update( + CUSTODIA_URL='http+unix://%s/secrets' % quote(CUSTODIA_SOCKET, safe=''), + # custodia_timeout=2, + CUSTODIA_CONTAINER='pwmgr', + SECRET_KEY='neHoch4doichu9el', + DEBUG=True, +) + + +class FlaskCustodia(object): + def __init__(self, app=None): + if app is not None: + self.init_app(app) + + def init_app(self, app): + url = app.config['CUSTODIA_URL'] + # timeout = app.config.get('custodia_timeout') + self._container = app.config['CUSTODIA_CONTAINER'] + self._client = CustodiaClient(url) + self._client.headers['REMOTE_USER'] = self._container + self.mkcontainer() + + def _genpath(self, key): + if set(key) & set('/.'): + raise ValueError(key) + return '/'.join((self._container, key)) + + def mkcontainer(self): + try: + self._client.create_container(self._container) + except HTTPError as e: + if e.response.status_code != 409: + raise + return False + else: + return True + + def items(self): + r = self._client.list_container(self._container) + return r.json() + + def get_simple(self, name): + return self._client.get_simple_key( + self._genpath(name)) + + def set_simple(self, name, value): + if not isinstance(value, basestring): + raise TypeError(value) + return self._client.set_simple_key( + self._genpath(name), value) + + def delete(self, name): + return self._client.del_key(self._genpath(name)) + + +flaskcustodia = FlaskCustodia(app) + + +@app.route('/') +def index(): + # flaskcustodia.set_simple('key', 'password') + items = flaskcustodia.items() + return render_template('index.html', items=items) + + +@app.route('/add', methods=['POST']) +def add_password(): + name = request.form['name'] + password = request.form['password'] + flaskcustodia.set_simple(name, password) + flash('New entry was successfully stored') + return redirect(url_for('index')) + + +@app.route('/delete', methods=['POST']) +def delete_password(): + name = request.form['name'] + flaskcustodia.delete(name) + flash('Entry was successfully deleted') + return redirect(url_for('index')) + +if __name__ == '__main__': + app.run() diff --git a/custodia_pwmgr/static/style.css b/custodia_pwmgr/static/style.css new file mode 100644 index 0000000..211e307 --- /dev/null +++ b/custodia_pwmgr/static/style.css @@ -0,0 +1,19 @@ +body { font-family: sans-serif; background: #eee; } +a, h1, h2 { color: #377BA8; } +h1, h2 { font-family: 'Georgia', serif; margin: 0; } +h1 { border-bottom: 2px solid #eee; } +h2 { font-size: 1.2em; } + +.page { margin: 2em auto; width: 35em; border: 5px solid #ccc; + padding: 0.8em; background: white; } +.entries { list-style: disc; margin: 0; padding: 0; } +.entries li { margin: 0.8em 1.2em; } +.entries li h2 { margin-left: -1em; } +.add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; } +.add-entry dl { font-weight: bold; } +.metanav { text-align: right; font-size: 0.8em; padding: 0.3em; + margin-bottom: 1em; background: #fafafa; } +.flash { background: #CEE5F5; padding: 0.5em; + border: 1px solid #AACBE2; } +.error { background: #F0D6D6; padding: 0.5em; } + diff --git a/custodia_pwmgr/templates/canvas.html b/custodia_pwmgr/templates/canvas.html new file mode 100644 index 0000000..136606d --- /dev/null +++ b/custodia_pwmgr/templates/canvas.html @@ -0,0 +1,11 @@ +<!doctype html> +<title>Custodia Example App</title> +<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}"> +<div class="page"> + <h1>Custodia Example App</h1> + {% for message in get_flashed_messages() %} + <div class="flash">{{ message }}</div> + {% endfor %} + {% block body %}{% endblock %} +</div> + diff --git a/custodia_pwmgr/templates/index.html b/custodia_pwmgr/templates/index.html new file mode 100644 index 0000000..e37ed82 --- /dev/null +++ b/custodia_pwmgr/templates/index.html @@ -0,0 +1,28 @@ +{% extends "canvas.html" %} +{% block body %} +<h2>Password Manager Example</h2> +<h3>Passwords</h3> +<ul class="entries"> +{% for item in items %} + <li>{{ item }} + <form action="{{ url_for('delete_password') }}" method="post"> + <input type="hidden" name="name" value="{{ item }}" /> + <input type="submit" value="Delete"> + </form> + </li> +{% else %} + <li>No passwords</li> +{% endfor %} +</ul> + +<h3>Add Password</h3> +<form action="{{ url_for('add_password') }}" method="post"> +<dl> + <dt>Name: + <dd><input type="text" name="name"> + <dt>Password: + <dd><input type="text" name="password"> + <dd><input type="submit" value="Submit"> +</dl> +</form> +{% endblock %} diff --git a/kubernetes/custodia-pwmgr-rc.yaml b/kubernetes/custodia-pwmgr-rc.yaml new file mode 100644 index 0000000..d6b66d2 --- /dev/null +++ b/kubernetes/custodia-pwmgr-rc.yaml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: ReplicationController +metadata: + name: custodia-pwmgr + labels: + name: custodia-pwmgr +spec: + replicas: 1 + selector: + name: custodia-pwmgr + version: v1 + template: + metadata: + labels: + name: custodia-pwmgr + version: v1 + secrets_namespace: pwmgr + spec: + containers: + - name: custodia-pwmgr + image: custodia-pwmgr + ports: + - containerPort: 5000 + name: custodia-pwmgr + env: + - name: CUSTODIA_SOCKET + value: /custodia/server_socket + volumeMounts: + - name: custodia + mountPath: /custodia + readOnly: true + volumes: + - name: custodia + hostPath: + path: /var/lib/custodia/client diff --git a/kubernetes/custodia-pwmgr-service.yaml b/kubernetes/custodia-pwmgr-service.yaml new file mode 100644 index 0000000..3cac5b2 --- /dev/null +++ b/kubernetes/custodia-pwmgr-service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + name: custodia-pwmgr + name: custodia-pwmgr +spec: + ports: + - port: 5000 + targetPort: 5000 + nodePort: 30666 + selector: + name: custodia-pwmgr + type: NodePort diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..31b9753 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +flask +requests +cryptography +jwcrypto +git+https://fedorapeople.org/cgit/simo/public_git/custodia.git @@ -0,0 +1,7 @@ +#!/bin/bash +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +export PYTHONPATH=$DIR/custodia +cd $DIR/custodia_pwmgr +python2.7 custodia_pwmgr.py +exit $? |
