A JSON gateway to query FreeIPA, built for the Fedora Account System.
The documentation is available at https://fasjson.readthedocs.io/
- documentation
- HTTPS
License: GNU General Public License v3.0
A JSON gateway to query FreeIPA, built for the Fedora Account System.
The documentation is available at https://fasjson.readthedocs.io/
We should provide a migration guide to allow developers easily identify which methods in the fasjson-client they will use instead of the method they are currently using in python-fedora.
The majority of apps use the following calls:
person_by_username
group_by_name
person_by_id
"/user/list"
PR here: fedora-infra/fasjson-client#14
We want to write a REST API in Python following the OpenAPI standard. There are many web frameworks and libraries that can help us with that.
Here's what I think we should consider:
The project must:
I haven't personally tried any of those frameworks but they look interesting. I think FastAPI is very much worth investigating, as it is based on solid libraries, has good references, and supports async. They have an interesting page listing other API projects that they took inspiration from.
This should be based on the investigation in #6.
Acceptance criteria:
DoD:
As a developer, I want an API endpoint to retrieve the open-api specification in JSON format.
specs
folder should be included in the project distributionRetrieve the project's open-api spec definition in a GET HTTP request.
Related Issue: #7
Example
from flask import Flask, Response
#subclasses the default flask.Response object
class AppResponse(Response):
charset = 'utf-8'
default_status = 200
default_mimetype = 'application/json'
@classmethod
def from_result(cls, status_code, data=None):
instance = cls(status=status_code)
if data:
instance.data = {
'result': data
}
return instance
@classmethod
def from_error(cls, e):
instance = cls(status=e.status_code)
instance.data = json.dumps({
'error': e.as_dict()
})
return instance
@classmethod
def force_type(cls, rv, environ=None):
#forces json parsing for all responses
if type(rv) != str:
rv = json.dumps(rv)
return super(AppResponse, cls).force_type(rv, environ)
app = Flask(__name__)
app.response_class = AppResponse
@app.route('/1')
def one():
return AppResponse.from_result(status_code=200, data={'a': 1})
@app.route('/2')
def two():
#works since the respone class is able to parse objects to jsonstring
return {'a': 1}
flask.Response
result
or error
responsesThe class being used as the flask response class.
As a Developer, I want to provide a health endpoint for monitoring tools
/v1/health
endpoint that returns fasjson health status;A new GET API method, an updated open api spec and docs.
Related Issue: #7
/v1/groups
- see OpenApi spec for detailsA valid REST API endpoint that follows the openapi spec and can be used from any HTTP client tool such as swagger, curl, etc.
/users/<username>/agreements/
.Uses flask_fas_openid here: https://github.com/fedora-infra/nuancier/blob/master/nuancier/__init__.py
Related Issue: #7
Example:
from flask import Flask
app = Flask(__name__)
class AppError(Exception):
def __init__(self, message=None, status_code=None, code=None, data=None):
self.status_code = status_code
self.message = message
self.code = code
self.data = None
def as_dict(self):
return {
'code': f'{self.status_code}.{self.code}' if self.code else self.status_code,
'message': self.message,
'data': self.data
}
def as_json(self):
return json.dumps(self.as_dict())
@app.route('/404')
def notfound():
#raising AppError will call handle_error function
raise AppError(message='dummy notfound error', status_code=404, code=100)
@app.route('/')
def root():
x = []
return {'value': x[50]} #raises IndexError
@app.errorhandler(AppError)
def handle_error(e):
r = Response(status=e.status_code, mimetype='application/json')
r.data = e.as_json()
return r
#this is reached if an unregistered/unexpected exception is raised (IndexError in this case)
@app.errorhandler(InternalServerError)
def handle_error_500(e):
original = getattr(e, 'original_exception', None)
r = Response(status=500, mimetype='application/json')
r.data = json.dumps({
'error': {
'code': '500.500',
'message': 'unexpected internal error',
'data': {
'exception': str(original)
}
}
})
return r
Documentation: https://flask.palletsprojects.com/en/1.1.x/errorhandling/
Flask app error responses being handled by the new exception class.
See: #52
Hacking on the project is currently a pretty involved thing, one needs a FreeIPA instance separate from the local machine (because FreeIPA automatically registers the host it's installed on as a client), one needs to install things to enable GSSAPI in Apache, etc.
It would be easier if there was a Vagrant setup (or equivalent) that a developer could use to make and test changes to the code.
For a Vagrant setup, the acceptance criteria would be :
vagrant up
to have a running VM with the project installed.DoD: all of the above are met.
Related Issue: #7
/v1/groups/$group_name/members
- see OpenAPI spec for detailsA valid REST API endpoint that follows the OpenAPI spec and can be used from any HTTP client tool such as swagger, curl, etc.
tox
to make managing and running common commands easierpyproject.toml
fileAll of the above are complete
Other team member reviewed
Related Issue: #7
I think it is good a idea to structure the application (api resources and libs if needed) in a "versioned" way so we easily manage and support different API versions such as /v1/groups/
.
This may require some kind of folder/project architecture re-factoring.
/v1/...
Project structure and http routing system using an API versioning scheme.
There are multiple places within the ansible repo where configs will need to be updated also. Most apps have some config defined there.
Acceptance criteria:
Using the list of applications created in #9 and the python library created in #8, all applications need to be ported to use the library.
AC:
DoD: all of the above.
See: #52
uses python-fedora to call the person_by_username method
pull request sent here: https://pagure.io/sigul/pull-request/3
The current FAS has an read-only API that some of the Fedora applications use. These applications include zodbot and the sigul bridge.
In the new freeIPA / secuiritas world, such applications will interact with fasjson (https://github.com/fedora-infra/fasjson).
This ticket is to track the porting of these applications over to the new fasjson API
(description updated based on @relrod comment below -- https://github.com/fedora-infra/securitas/issues/56#issuecomment-581444027 )
Code lives at https://pagure.io/fedora-commops/geofp
It uses:
It's a simple class to get Geographical information from the users account
elections sets up python-fedora here: https://pagure.io/elections/blob/develop/f/fedora_elections/__init__.py#_68
and uses it to make a few calls (mostly person_by_username) throughout the app.
This should be changed to use fasjson_client instead (based on a configuration setting) so that once redeployed it wil use the new backend.
Things to think about when designing the API:
Acceptance criteria:
DoD: all of the above
membership-map.py and membership-mwclient.py here: https://pagure.io/fedora-infra/ansible/blob/master/f/roles/membership-map/build/templates both use python-fedora to communicate with FAS.
Related Issue: #7
/v1/users/$username
- see the OpenAPI spec for detailsA valid REST API endpoint that follows the OpenAPI spec and can be used from any HTTP client tool such as swagger, curl, etc.
Authorization: Negotiate ...
)Authenticated API requests and ldap operations working.
Project and API documentation in HTML format
Dependabot can't resolve your Python dependency files.
As a result, Dependabot couldn't update your dependencies.
The error Dependabot encountered was:
Creating virtualenv fasjson-MJrliQxI-py3.8 in /home/dependabot/.cache/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies...
[PackageNotFound]
Package requests-kerberos (0.12.0) not found.
If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.
See: #52
https://pagure.io/fedora-badges has a dependency on python-fedora. Once python-fedora has been updated so too should this module.
As a developer, I'd like to have fasjson deployed alongside securitas in CommuniShift, in a CD manner.
It may be more complex than securitas because fasjson uses Kerberos / GSSAPI to authenticate.
Acceptance criteria:
DoD: all of the above are met.
See: #52
https://github.com/fedora-infra/fedmsg_meta_fedora_infrastructure/blob/develop/fedmsg_meta_fedora_infrastructure/fasshim.py it uses python-fedora to hit '/user/list'
https://pagure.io/fedscm-admin/blob/master/f/fedscm_admin/fas.py
closing as duplicate
CentOS uses x509 certificates to access build nodes, we need to provide a way for those users to get their certificates.
cert_find
IPA command)cert_show
IPA command).cert_request
IPA command)cert_status
IPA command)For example, there could be:
/certs/
namespace where certificates could be queried with ?users=<connected_user>
, calling cert_find
/certs/<serial>
endpoint where a certificate would be retrieved with cert_show
./certs/request
endpoint where CSRs could be uploaded. It could return the signed certificate in a JSON dict, that would also contain the URL to that certificate in the API as a hyperlink.Related Issue: #7
A valid REST API endpoint that follows the OpenAPI spec and can be used from any HTTP client tool such as swagger, curl, etc.
A good first step would be to look into the infra Ansible repo for the fedoraDummyUserPassword
variable, it means that this app is using the dummy FAS account to make queries.
Another way would be to grep all our source codes for the fedoraproject.org/accounts
URL.
Once we have the list we need to look at what those apps do in their FAS queries. Whether it's read-only or not, what endpoints they are querying, etc.
AC:
DoD: All AC are met
Uses python-fedora
to make basic FAS calls here: https://pagure.io/fedscm-admin/blob/master/f/fedscm_admin/fas.py
See: #52
LDAP queries are not bound as the connecting user but with the host's keytab.
$ klist -A
Ticket cache: KCM:1000
Default principal: [email protected]
Valid starting Expires Service principal
04/23/2020 09:40:04 04/24/2020 09:39:53 HTTP/[email protected]
04/23/2020 09:39:58 04/24/2020 09:39:53 krbtgt/[email protected]
04/23/2020 10:14:04 04/24/2020 09:39:53 HTTP/[email protected]
04/23/2020 13:13:05 04/24/2020 09:39:53 ldap/[email protected]
$ curl --negotiate -u : http://fasjson.example.test/fasjson/v1/me
{"result":{"info":{"cn":["services","accounts"],"dc":["example","test"],"krbprincipalname":"http/[email protected]"},"raw":"dn: krbprincipalname=http/[email protected],cn=services,cn=accounts,dc=example,dc=test"}}
FASJSON should return the DN of [email protected]
and not the service.
Apache's mod_wsgi shows [email protected]
in the log files and sets GSS_NAME
to that value as well. It also sets KRB5CCNAME
to FILE:/run/fasjson/ccaches/[email protected]
in the request's environment.
The bind is done with:
self.conn.sasl_interactive_bind_s(
"", ldap.sasl.sasl({}, "GSS-SPNEGO")
)
@tiran any idea what is going on?
the ansible playbook here: https://infrastructure.fedoraproject.org/cgit/ansible.git/tree/roles/distgit/pagure/files/fas2.py creates the requests to contact FAS, these will need to be updated.
this possibly needs to be consolidated with python-fedora once that update happens.
the-new-hotness config.toml seems to use the old FAS dummy user account here: https://infrastructure.fedoraproject.org/cgit/ansible.git/tree/roles/openshift-apps/the-new-hotness/templates/config.toml#n153
As a developer, I want a script that generates an open-api spec 2.0 file (aka swagger 2) from a open-api spec 3.0 file
A swagger spec file being generated from a open-api spec 3.0 file.
Uses flask fas openID here: https://github.com/fedora-infra/mirrormanager2/blob/master/mirrormanager2/app.py#L92
A python library would be most useful, it would be based on the work in #7 and could take advantage of the schema that the API publishes.
AC:
DoD:
Code lives at: https://pagure.io/fedora-infra/distgit-bugzilla-sync/
It uses:
https://pagure.io/fedora-infra/distgit-bugzilla-sync/blob/master/f/distgit_bugzilla_sync/script.py
Each of the consumers below need to be updated to use fasjson instead of FAS. They are simple config changes to match the updates from their respective tickets.
A/C
See: #52
https://github.com/fedora-infra/fmn/blob/abfc610bd443df2ae588f3d5ce4e1c689cd59c71/fmn/fmn_fasshim.py
same as fedmsg_meta_fedora_infrastructure #58
Creation of integration & unit tests
Coverage
Tests to be completed identified and documented
Reviewed by team/sign off by team
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.