Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Heimes <[email protected]>
  • Loading branch information
tiran committed Nov 19, 2019
0 parents commit d99ffaa
Show file tree
Hide file tree
Showing 19 changed files with 1,367 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/build/
/dist/
/src/*.egg-info
__pycache__
*.pyc
*.pyo
.tox
*.rpm
*.tar.gz
MANIFEST
674 changes: 674 additions & 0 deletions COPYING

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions MANINFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include README.md COPYING
include setup.cfg pyproject.toml Makefile
include fasjson.wsgi
recursive-include config *.conf
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
BLACK=black

all: lint

lint:
$(BLACK) --check .

black:
$(BLACK) .
88 changes: 88 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Fedora Account System / IPA JSON gateway

**PROOF OF CONCEPT**

## Installation

Install dependencies

```
dnf install ipa-client httpd mod_auth_gssapi mod_session python3-mod_wsgi python3-dns python3-flask python3-gssapi python3-ldap python3-pip python3-wheel
```

Install WSGI app

```
pip-3 install .
cp fasjson.wsgi /srv/
```

Enroll the system as an IPA client

```
$ ipa-client-install
```

Get service keytab for HTTPd

```
ipa service-add HTTP/$(hostname)
ipa-getkeytab -p HTTP/$(hostname) -k /var/lib/gssproxy/httpd.keytab
chown root:root /var/lib/gssproxy/httpd.keytab
chmod 640 /var/lib/gssproxy/httpd.keytab
```

Configure GSSProxy for Apache

```
cp config/gssproxy-fasjson.conf /etc/gssproxy/99-fasjson.conf
systemctl enable gssproxy.service
systemctl restart gssproxy.service
```

Configure temporary files

```
cp config/tmpfiles-fasjson.conf /etc/tmpfiles.d/fasjson.conf
systemd-tmpfiles --create
```

Tune SELinux Policy

```
setsebool -P httpd_can_connect_ldap=on
```

Configure Apache

```
mkdir mkdir -p /etc/systemd/system/httpd.service.d
cp config/systemd-httpd-service-fasjson.conf /etc/systemd/system/httpd.service.d/fasjson.conf
cp config/httpd-fasjson.conf /etc/httpd/conf.d/fasjson.conf
systemctl daemon-reload
systemctl enable httpd.service
systemctl restart httpd.service
```

## Usage

```
$ kinit
$ curl --negotiate -u : http://$(hostname)/fasjson/groups
["admins","ipausers","editors","trust admins"]
$ curl --negotiate -u : http://$(hostname)/fasjson/group/admins
["admin"]
$ curl --negotiate -u : http://$(hostname)/fasjson/user/admin
{"gecos":"Administrator"}
```

## TODO

A lot!

* tests
* documentation
* CI
* error handling
* HTTPS
* JSON return value
13 changes: 13 additions & 0 deletions config/gssproxy-fasjson.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#
# /etc/gssproxy/99-fasjson.conf
#

[service/fasjson-httpd]
mechs = krb5
cred_store = keytab:/var/lib/gssproxy/httpd.keytab
cred_store = client_keytab:/var/lib/gssproxy/httpd.keytab
allow_protocol_transition = true
allow_client_ccache_sync = true
cred_usage = both
euid = apache

37 changes: 37 additions & 0 deletions config/httpd-fasjson.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# /etc/httpd/conf.d/fasjson.conf
#

WSGISocketPrefix /run/httpd/wsgi
WSGIDaemonProcess fasjson processes=4 threads=1 maximum-requests=500 \
display-name=%{GROUP} socket-timeout=2147483647 \
lang=C.UTF-8 locale=C.UTF-8
WSGIImportScript /usr/share/fasjson/fasjson.wsgi \
process-group=fasjson application-group=fasjson
WSGIScriptAlias /fasjson /usr/share/fasjson/fasjson.wsgi
WSGIScriptReloading Off

<Location "/fasjson">
AuthType GSSAPI
AuthName "Kerberos Login"
GssapiUseSessions On
Session On
SessionCookieName ipa_session path=/fasjson;httponly;secure;
SessionHeader IPASESSION
GssapiSessionKey file:/run/fasjson/session.key

GssapiImpersonate On
GssapiDelegCcacheDir /run/fasjson/ccaches
GssapiDelegCcachePerms mode:0660
GssapiUseS4U2Proxy on
GssapiAllowedMech krb5

Require valid-user
WSGIProcessGroup fasjson
WSGIApplicationGroup fasjson
Header always append X-Frame-Options DENY
Header always append Content-Security-Policy "frame-ancestors 'none'"
Header unset Set-Cookie
Header unset ETag
FileETag None
</Location>
7 changes: 7 additions & 0 deletions config/systemd-httpd-service-fasjson.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#
# /usr/lib/systemd/system/httpd.service.d/fasjson.conf
#

[Service]
Environment=KRB5CCNAME=/tmp/krb5cc-httpd
Environment=GSS_USE_PROXY=yes
6 changes: 6 additions & 0 deletions config/tmpfiles-fasjson.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# /usr/lib/tmpfiles.d/fasjson.conf
#

d /run/fasjson 0770 apache apache
d /run/fasjson/ccaches 0770 apache apache
118 changes: 118 additions & 0 deletions fasjson.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
%global debug_package %{nil}
%global ipa_version 4.8.0

Name: fasjson
Version: 0.0.1
Release: 1%{?dist}
Summary: JSON REST API for Fedora Account System

BuildArch: noarch

License: GPL
URL: https://github.com/fedora-infra/fasjson
Source0: https://github.com/fedora-infra/fasjson/archive/%{version}.tar.gz

BuildRequires: python3-devel
BuildRequires: python3-setuptools
BuildRequires: systemd

Requires: python3-fasjson
Requires: gssproxy
Requires: httpd
Requires: mod_auth_gssapi
Requires: mod_session
Requires: python3-mod_wsgi
%if 0%{?rhel}
Conflicts: ipa-server
Requires: ipa-client >= %{ipa_version}
%else
Conflicts: freeipa-server
Requires: freeipa-client >= %{ipa_version}
%endif
%{?systemd_requires}


%description
JSON REST API for Fedora Account System


%package -n python3-fasjson
Summary: FAS JSON REST API server implementation
Requires: python3-dns
Requires: python3-flask
Requires: python3-gssapi
Requires: python3-ldap


%description -n python3-fasjson
Python 3 flask app for fasjson


%prep
%autosetup


%build
%py3_build
touch debugfiles.list


%install
rm -rf $RPM_BUILD_ROOT
%py3_install

%__mkdir_p %{buildroot}%{_usr}/share/fasjson
cp fasjson.wsgi %{buildroot}%{_usr}/share/fasjson

%__mkdir_p %{buildroot}%{_sysconfdir}/gssproxy
cp config/gssproxy-fasjson.conf %{buildroot}%{_sysconfdir}/gssproxy/99-fasjson.conf

%__mkdir_p %{buildroot}%{_unitdir}/httpd.service.d
cp config/systemd-httpd-service-fasjson.conf %{buildroot}/%{_unitdir}/httpd.service.d/fasjson.conf

%__mkdir_p %{buildroot}%{_sysconfdir}/httpd/conf.d
cp config/httpd-fasjson.conf %{buildroot}%{_sysconfdir}/httpd/conf.d/fasjson.conf

%__mkdir_p %{buildroot}%{_tmpfilesdir}
cp config/tmpfiles-fasjson.conf %{buildroot}%{_tmpfilesdir}/fasjson.conf


%post
%tmpfiles_create %{_tmpfilesdir}/fasjson.conf
%systemd_post gssproxy.service httpd.service


%preun
%systemd_preun gssproxy.service httpd.service


%postun
%systemd_postun gssproxy.service httpd.service


%posttrans
systemctl daemon-reload
systemctl enable --now gssproxy.service
systemctl restart gssproxy.service
systemctl try-restart httpd.service


%files
%config %{_sysconfdir}/gssproxy/99-fasjson.conf
%config %{_unitdir}/httpd.service.d/fasjson.conf
%config(noreplace) %{_sysconfdir}/httpd/conf.d/fasjson.conf
%config %{_tmpfilesdir}/fasjson.conf
%dir %{_usr}/share/fasjson
%{_usr}/share/fasjson/fasjson.wsgi


%files -n python3-fasjson
%license COPYING
%doc README.md
%{python3_sitelib}/fasjson
%{python3_sitelib}/fasjson*.egg-info


%changelog
* Tue Nov 19 2019 Christian Heimes <[email protected]> - 0.0.1-1
- Initial release
1 change: 1 addition & 0 deletions fasjson.wsgi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from fasjson import app as application
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[tool.black]
line-length = 78
5 changes: 5 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[metadata]
license_files = COPYING

[bdist_wheel]
universal = 1
22 changes: 22 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from setuptools import setup

setup(
name="fasjson",
author="Christian Heimes",
version="0.0.1",
author_email="[email protected]",
description="Read-only REST-like API for Fedora Account System",
package_dir={"": "src"},
packages=["fasjson", "fasjson.plugins"],
classifiers=[
"Development Status :: 2 - Pre-Alpha",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Intended Audience :: Developers",
"Topic :: Security",
"Topic :: Software Development :: Libraries :: Python Modules",
],
install_requires=["flask", "python-ldap", "dnspython", "gssapi"],
python_requires=">=3.6",
)
48 changes: 48 additions & 0 deletions src/fasjson/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#
# Copyright (C) 2019 Christian Heimes <[email protected]>
# See COPYING for license
#
"""Read-only REST-like API for Fedora Account System
"""
import flask
from werkzeug.routing import BaseConverter

from .plugins.gss import FlaskGSSAPI
from .plugins.ipacfg import IPAConfig
from .plugins.ldapconn import get_ldap_conn


app = flask.Flask(__name__)
FlaskGSSAPI(app)
IPAConfig(app)


class UserGroupConverter(BaseConverter):
regex = "[a-zA-Z][a-zA-Z0-9_.-]{0,63}"


app.url_map.converters["usergroup"] = UserGroupConverter


@app.route("/")
def index():
conn = get_ldap_conn()
return conn.whoami()


@app.route("/groups")
def groups():
conn = get_ldap_conn()
return flask.jsonify(list(conn.get_groups()))


@app.route("/group/<usergroup:groupname>")
def group(groupname):
conn = get_ldap_conn()
return flask.jsonify(list(conn.get_group_members(groupname)))


@app.route("/user/<usergroup:username>")
def user(username):
conn = get_ldap_conn()
return flask.jsonify(conn.get_user(username))
6 changes: 6 additions & 0 deletions src/fasjson/plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# Copyright (C) 2019 Christian Heimes <[email protected]>
# See COPYING for license
#
"""Plugins
"""
Loading

0 comments on commit d99ffaa

Please sign in to comment.