Accessing EDG APIs with different types of authentication
In this section we will demonstrate how to call EDG Web APIs using Python for three different forms of authentication supported by EDG. For it, you will require a basic understanding of Python. For each example, we provide Python code to execute the EDG Web Service “exportRDFFile”. For more on using the exportRDFFile via Swagger and cURL, see Downloading an asset collection as RDF.
Contents
1. Using Basic authentication
Basic authentication relies on a Base64 encoded Authorization
header whose value consists of the word Basic
followed by a space followed by the Base64 encoded name:password
. This is better suited for service-only access because the only way a user can log out is to shut down their browser. The URL with header information can be submitted with authentication information.
Here’s an example using Python to access the EDG exportRDFFile Web Service.
1import argparse
2import requests
3import base64
4import getpass
5
6
7def main():
8 parser = argparse.ArgumentParser(
9 description="Make a GET request to a specified URL with credentials."
10 )
11 parser.add_argument("--username", required=True, help="Username for authentication")
12 parser.add_argument("--host", required=True, help="Hostname or IP address")
13 parser.add_argument(
14 "--asset_collection", required=True, help="Asset collection name"
15 )
16 parser.add_argument("--format", required=True, help="Format of export")
17 args = parser.parse_args()
18
19 # Prompt for password securely
20 password = getpass.getpass(prompt="Password: ")
21
22 # Encode username and password as base64
23 credentials = base64.b64encode(f"{args.username}:{password}".encode()).decode()
24
25 # Construct URL
26 url = f"http://{args.host}/service/{args.asset_collection}/tbs/exportRDFFile?format={args.format}"
27
28 try:
29 # Make GET request with Authorization header
30 response = requests.get(
31 url, headers={"Authorization": f"Basic {credentials}"}, verify=False
32 )
33
34 # Raise an HTTPError for bad responses
35 response.raise_for_status()
36
37 # Print the response text
38 print(response.text)
39
40 except requests.exceptions.HTTPError as http_err:
41 print(f"HTTP error occurred: {http_err}")
42 except requests.exceptions.RequestException as req_err:
43 print(f"Request error occurred: {req_err}")
44
45
46if __name__ == "__main__":
47 main()
To run the service use the following command -
python exportRDFFile.py --username <username> --host <localhost> --asset_collection <asset_collection> --format <format>
When it prompts, enter your password. For example, running on an EDG instance locally with basic authentication, e.g. username admin, use the following command: python exportRDFFile_basic_auth.py --username "admin" --host "localhost:8083/tbl" --asset_collection "kennedy_family" --format "turtle"
. Then when prompted type in your password. On succesfully executing the script, it should print the kennedy_family ttl to the terminal/command window.
For secure access, web services should use HTTPS encryption.
2. Using Form-based authentication
Access using Form-based authentication, while not recommended, is possible using cookies generated by the server. The method we give here, using the following Python script, is to request an HTTP cookie that can be used in subsequent requests. The python script expects the same arguments as for basic auth, i.e. username, host, the asset collection name and the format. The inputs for these would be the same as for basic auth, except for host, which if you are running EDG studio locally with form based authentication would be "http://localhost:8083/tbl"
. You enter your password again when you receive a prompt.
The main function specifies the required arguments, and then proceeds to create a session to handle the cookies. Next it executes the login function using this session.
The login function takes the host URL and performs an initial
POST
request to obtain a cookie from the server.The login script then performs a second
POST
request to login, now making use of the username and password as parameters.On successful login, the python script uses the session to run subsequent http request. In this example we once again call the EDG exportRDFFile web service.
1import argparse
2import requests
3import sys
4import getpass
5
6
7def login(session, input_url, username, password):
8 try:
9 # Perform the initial POST request to obtain cookies
10 response = session.post(input_url)
11
12 # Check if the request was successful
13 response.raise_for_status()
14
15 # Perform the second POST request with cookies
16 login_data = {"j_username": username, "j_password": password}
17
18 login_headers = {"User-Agent": "Mozilla/5.0"}
19
20 login_url = input_url + "/swp?_viewName=home"
21 response = session.post(
22 login_url, data=login_data, headers=login_headers, allow_redirects=False
23 )
24
25 # Perform the third POST request with cookies to complete the login
26 j_security_check_url = input_url + "/j_security_check"
27
28 response = session.post(
29 j_security_check_url, data=login_data, headers=login_headers
30 )
31
32 # Check if the login was successful
33 response.raise_for_status()
34
35 except requests.exceptions.RequestException as e:
36 print(f"Error during login: {e}")
37 sys.exit(1)
38
39
40def main():
41 parser = argparse.ArgumentParser(
42 description="Make requests with login to a specified URL."
43 )
44 parser.add_argument("--username", required=True, help="Username for authentication")
45 parser.add_argument("--host", required=True, help="Input URL")
46 parser.add_argument(
47 "--asset_collection", required=True, help="Asset collection name"
48 )
49 parser.add_argument("--format", required=True, help="Export format")
50 args = parser.parse_args()
51
52 try:
53 # Prompt for password securely
54 password = getpass.getpass(prompt="Password: ")
55
56 # Create a session to handle cookies
57 session = requests.Session()
58
59 # Perform login
60 login(session, args.host, args.username, password)
61
62 # Now you can use the session for subsequent requests
63
64 # Perform the GET request using success cookies
65 base_url = f"{args.host}/service/{args.asset_collection}/tbs/exportRDFFile?format={args.format}"
66 headers = {"accept": "application/json"}
67
68 response = session.get(base_url, headers=headers)
69
70 if response.status_code == 200:
71 print("Request was successful")
72 print(response.text)
73 else:
74 print(f"Request failed with status code {response.status_code}")
75 print(response.text)
76
77 except requests.exceptions.RequestException as e:
78 print(f"Error making the request: {e}")
79 sys.exit(1)
80
81
82if __name__ == "__main__":
83 main()
Use the following command to execute the script python exportRDFFile_basic_auth.py --username "admin" --host "http://localhost:8083/tbl" --asset_collection "kennedy_family" --format "turtle"
. Then again, type in your password.
On successfully executing the script, it should print the kennedy_family ttl to the terminal/command window.
For secure access, web services should use HTTPS encryption.
3. Using OAuth authentication
The following piece of Python script provides a means for calling the exportRDFFile when using OAuth authentication. The code takes the following parameters; host, the asset collection name and the format. The authentication server, client id and scope could also be potentially passed in as parameters. Here, we hard code them. We also prompt the use for their client secret. Again, this could be passed as a parameter.
The code is broken into a main function and login function. The login function prompts the user for their client secret. This is then used to generate the “access_token”, which is returned by the function.
The main function then takes the three parameters, provides hard coded auth_server_url and client_id. Here we assemble the API URL from the parameters we pass in, but you can replace this with any API URL. The code then generates the access token hourly, prompting each time for the client secret.
On successful execution, it will write the response data to the terminal/command line.
1#!/usr/local/bin/python3
2#
3"""
4Sample API client using OAuth 2 client credentials flow. It will will repeat
5an API call every hour and generate a new token as needed.
6
71. Call API
82. If access token is expired, use the client_secret to get a new one
93. Repeat
10
11@author: TopQuadrant
12"""
13import argparse
14import getpass
15import json
16import time
17import urllib.parse
18import urllib.request
19import ssl
20
21
22def authenticate(url, client_id):
23 """
24 Authenticates the client and generates a new access token.
25 """
26 client_secret = getpass.getpass("Client secret: ")
27 request_data = {
28 "client_id": client_id,
29 "client_secret": client_secret,
30 "grant_type": "client_credentials",
31 "scope": "api://uuid/.default", # add your scope here
32 }
33 encoded_data = urllib.parse.urlencode(request_data)
34 binary_data = encoded_data.encode("ascii")
35 request = urllib.request.Request(url)
36 print("Getting token...")
37 response = urllib.request.urlopen(request, binary_data)
38 # Just to be safe...
39 client_secret = None
40 tokens = json.load(response)
41 access_token = tokens["access_token"]
42 return access_token
43
44
45def main():
46 parser = argparse.ArgumentParser(
47 description="Make requests with login to a specified URL."
48 )
49
50 parser.add_argument("--host", required=True, help="Input URL")
51 parser.add_argument(
52 "--asset_collection", required=True, help="Asset collection name"
53 )
54 parser.add_argument("--format", required=True, help="Export format")
55 args = parser.parse_args()
56
57 # Copy your authorization server URL and paste it here
58 auth_server_url = "https://your.adfs.server/adfs/oauth2/token"
59 # Copy your client ID and paste it here
60 client_id = "12345678-90ab-cdef-1234-567890abcdef"
61 # Copy your EDG API URL and paste it here
62 api_url = f"https://{args.host}/edg/tbl/service/{args.asset_collection}/tbs/exportRDFFile?format={args.format}"
63 # Copy your initial access_token you got from the authorization server and paste it here
64 access_token = ""
65
66 # Run the API call once per hour
67 print("Running hourly process...")
68 while True:
69 # What time is it?
70 print(time.strftime("%c"))
71 # Use the access token
72 auth_header = {"Authorization": "Bearer " + access_token}
73 # Make a request
74 request = urllib.request.Request(api_url, None, auth_header)
75 try:
76 response = urllib.request.urlopen(request)
77 print("Response status was " + str(response.getcode()))
78 except urllib.error.HTTPError as error:
79 # Check status code
80 if error.code == 401:
81 # Need to use client_secret to get a new token
82 access_token = authenticate(auth_server_url, client_id)
83 # Use the new access token
84 auth_header = {"Authorization": "Bearer " + access_token}
85 # Repeat the request
86 request = urllib.request.Request(api_url, None, auth_header)
87 # Get the response
88 response = urllib.request.urlopen(request)
89 print("Response status was " + str(response.getcode()))
90 # Do something useful with the response. (Your biz logic goes here)
91 result = print(response.read())
92 #
93 # Wait until next time
94 print("Sleeping.")
95 time.sleep(3600)
96
97
98if __name__ == "__main__":
99 main()
Use the following command to execute the script python exportRDFFile_oauth_auth.py --username --host "localhost:8083" --asset_collection "kennedy_family" --format "turtle"