From d45a17b69ab1ae024f665a3519cb9edb02733424 Mon Sep 17 00:00:00 2001 From: Saira Bano Date: Tue, 27 Aug 2024 16:45:30 +0200 Subject: [PATCH 1/3] chore: example to create secure fiware header --- .../e13_ngsi_v2_secure_fiware_headers.py | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 examples/ngsi_v2/e13_ngsi_v2_secure_fiware_headers.py diff --git a/examples/ngsi_v2/e13_ngsi_v2_secure_fiware_headers.py b/examples/ngsi_v2/e13_ngsi_v2_secure_fiware_headers.py new file mode 100644 index 00000000..01bf249f --- /dev/null +++ b/examples/ngsi_v2/e13_ngsi_v2_secure_fiware_headers.py @@ -0,0 +1,111 @@ +import os + +import requests +import urllib3 + +from filip.clients.ngsi_v2 import ContextBrokerClient +from filip.config import settings +from filip.models.base import FiwareHeaderSecure + +urllib3.disable_warnings() +session = requests.Session() +CB_URL = settings.CB_URL +SERVICE = 'filip' +SERVICE_PATH = '/' +CLIENT_ID = 'client_id' +CLIENT_SECRET = 'client_secret' +KEYCLOAK_HOST = 'https://keycloak.example.com' + + +class KeycloakPython: + def __init__(self, keycloak_host=None, client_id=None, client_secret=None): + """ + - Initialze the Keycloak Host , Client ID and Client secret. + - If no parameters are passed .env file is used + - Priority : function parameters > Class Instatiation > .env file + """ + # if keycloak_host == None: + # self.keycloak_host = os.getenv('KEYCLOAK_HOST') + # else: + # self.keycloak_host = keycloak_host + self.keycloak_host = os.getenv('KEYCLOAK_HOST') if keycloak_host == None else keycloak_host + self.client_id = os.getenv('CLIENT_ID') if client_id == None else client_id + self.client_secret = os.getenv('CLIENT_SECRET') if client_secret == None else client_secret + + def get_access_token(self, keycloak_host=None, client_id=None, client_secret=None): + """ + - Get access token for a given client id and client secret. + """ + self.keycloak_host = keycloak_host if keycloak_host != None else self.keycloak_host + self.client_id = client_id if client_id != None else self.client_id + self.client_secret = client_secret if client_secret != None else self.client_secret + self.data = {'client_id': self.client_id, + 'client_secret': self.client_secret, + 'scope': 'email', + 'grant_type': 'client_credentials', + } + try: + headers = {"content-type": "application/x-www-form-urlencoded"} + access_data = requests.post(self.keycloak_host, data=self.data, headers=headers) + expires_in = access_data.json()['expires_in'] + access_token = access_data.json()['access_token'] + return access_token, expires_in + except requests.exceptions.RequestException as err: + raise KeycloakPythonException(err.args[0]) + + def get_data(self, client_host, headers={}, keycloak_host=None, client_id=None, client_secret=None): + """ + - Get data for a given api. + - Mandatory input - Target api, fiware-service and fiware-servicepath headers + - Optional Inmput - Keycloak host, Client ID, Client Secret + """ + access_token, expires_in = self.get_access_token(keycloak_host=keycloak_host, client_id=client_id, + client_secret=client_secret) + headers['Authorization'] = 'Bearer %s' % (access_token) + response = requests.get(client_host, headers=headers) + return response.text + + def post_data(self, client_host, data, headers={}, keycloak_host=None, client_id=None, client_secret=None): + """ + - Post data for a given api. + - Mandatory input - Target api, headers, request body. + - Optional Inmput - Keycloak host, Client ID, Client Secret. + """ + access_token, expires_in = self.get_access_token(keycloak_host=keycloak_host, client_id=client_id, + client_secret=client_secret) + headers['Content-Type'] = 'application/json' + headers['Authorization'] = 'Bearer %s' % (access_token) + response = requests.post(client_host, data=data, headers=headers) + return response + + def patch_data(self, client_host, json, headers={}, keycloak_host=None, client_id=None, client_secret=None): + """ + - Patch data for a given api. + - Mandatory input - Target api, headers, request body. + - Optional Inmput - Keycloak host, Client ID, Client Secret. + """ + access_token, expires_in = self.get_access_token(keycloak_host=keycloak_host, client_id=client_id, + client_secret=client_secret) + headers['Content-Type'] = 'application/json' + headers['Authorization'] = 'Bearer %s' % (access_token) + response = requests.patch(url=client_host, json=json, headers=headers) + return response + + +class KeycloakPythonException(Exception): + def __init__(self, message): + self.message = message + super().__init__(self.message) + + +if __name__ == "__main__": + # get token from keycloak + token, in_sec = KeycloakPython(KEYCLOAK_HOST, CLIENT_ID, CLIENT_SECRET).get_access_token() + + # create secure fiware header with authorisation token + fiware_header = FiwareHeaderSecure(service=SERVICE, + service_path=SERVICE_PATH, + authorization='Bearer %s' % token) + + # create a context broker client + cb_client = ContextBrokerClient(url=CB_URL, fiware_header=fiware_header, session=session) From 18b23cc4cc01f35b349c13f045aa600e609f0cb9 Mon Sep 17 00:00:00 2001 From: Saira Bano Date: Mon, 21 Oct 2024 12:26:16 +0200 Subject: [PATCH 2/3] docs: included comments --- examples/ngsi_v2/e13_ngsi_v2_secure_fiware_headers.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/ngsi_v2/e13_ngsi_v2_secure_fiware_headers.py b/examples/ngsi_v2/e13_ngsi_v2_secure_fiware_headers.py index 01bf249f..89ac913a 100644 --- a/examples/ngsi_v2/e13_ngsi_v2_secure_fiware_headers.py +++ b/examples/ngsi_v2/e13_ngsi_v2_secure_fiware_headers.py @@ -1,3 +1,7 @@ +""" +# This example shows how to generate an access token from an authnetication srever in order to access Fiware services +# which are protected behind an authentication/authorisation layer. +""" import os import requests @@ -10,10 +14,14 @@ urllib3.disable_warnings() session = requests.Session() CB_URL = settings.CB_URL +# FIWARE-Service SERVICE = 'filip' +# FIWARE-Servicepath SERVICE_PATH = '/' +# Provide client credentials which are used when generating access token from authentication server CLIENT_ID = 'client_id' CLIENT_SECRET = 'client_secret' +# TODO: Please adapt it according to your authentication server which is generating access token for the service KEYCLOAK_HOST = 'https://keycloak.example.com' @@ -109,3 +117,5 @@ def __init__(self, message): # create a context broker client cb_client = ContextBrokerClient(url=CB_URL, fiware_header=fiware_header, session=session) + # you don't need to set any extra parameter for requesting the service besides setting session in the client object + entity_list = cb_client.get_entity_list() From 891fcbf69067d312be01e7c5243c20591bd829cc Mon Sep 17 00:00:00 2001 From: JunsongDu <101181614+djs0109@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:51:01 +0200 Subject: [PATCH 3/3] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ce4683e..f61ccde3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### v0.6.X +- add: Tutorial for connecting with secured endpoints ([#319](https://github.com/RWTH-EBC/FiLiP/pull/319)) + ### v0.5.0 - update: allow duplicated name in device, check uniqueness of object_id ([#279](https://github.com/RWTH-EBC/FiLiP/pull/279)) - update: upgrade dependency of `paho-mqtt` to v2 ([#273](https://github.com/RWTH-EBC/FiLiP/pull/273/))