LP#169625: Support script for working with OverDrive API
authorJeff Davis <jdavis@sitka.bclibraries.ca>
Thu, 8 Jun 2017 18:09:04 +0000 (11:09 -0700)
committerGalen Charlton <gmc@equinoxinitiative.org>
Thu, 4 Mar 2021 15:28:29 +0000 (10:28 -0500)
Adds a script, overdrive-api-checker.pl, for testing the
OverDrive API from the command line.

USAGE:
    Open-ILS/src/support-scripts/overdrive-api-checker.pl --get-token --key <client-key> --secret <client-secret>
    Open-ILS/src/support-scripts/overdrive-api-checker.pl --account <account_id> --token <basic_token> [ --endpoint https://api.overdrive.com/v1/libraries/1234 [ --content <content> ] ]
    Open-ILS/src/support-scripts/overdrive-api-checker.pl --account <account_id> --token <basic_token> --oauth-only
    Open-ILS/src/support-scripts/overdrive-api-checker.pl --account <account_id> --token <basic_token> --patron-auth [ --endpoint https://oauth-patron.overdrive.com/patrontoken ] --barcode <barcode> [ --password <password> ] --websiteid <websiteid> --authorizationname <authorizationname>

OPTIONS:
    --get-token
        Generate OverDrive API basic token.
    --key
        Client key supplied by OverDrive.  Required with --get-token.
    --secret
        Client secret supplied by OverDrive.  Required with --get-token.
    --token
        Your OverDrive API basic token (clientKey:clientSecret, Base64-encoded).
        Required unless using --get-token.
    --account
        Your OverDrive API account ID (e.g. 1234).  Not required for generating
        a basic token; required for everything else.
    --oauth-endpoint
        OverDrive API endpoint for OAuth token requests.
        Default: https://oauth.overdrive.com/token.
    --endpoint
        OverDrive API endpoint that you wish to test.
        Default: https://api.overdrive.com/v1/libraries/<account>
    --content
        JSON content of main API request.  Required only if you have specified
        an endpoint that expects JSON message content.
    --oauth-only
        Only request an OAuth token; do not attempt further API requests.
    --patron-auth
        Submit a patron authentication request.
    --barcode
        Patron barcode.  Required with --patron-auth.
    --password
        Patron password.  Required with --patron-auth if your library requires
        password for patron authentication.
    --websiteid
        Website ID supplied by OverDrive.  Required with --patron-auth.
    --authorizationname
        ILS name supplied by OverDrive.  Required with --patron-auth.
    --verbose
        Print full HTTP requests and responses.
    --help
        Print this help message.

EXAMPLES:

    To generate your basic token, given a client key and client secret supplied
    by OverDrive:

    Open-ILS/src/support-scripts/overdrive-api-checker.pl --get-token --key <client-key> --secret <client-secret>

    To send a basic API request (this is useful for validating your client
    credentials and determining whether the OverDrive API is currently
    available):

    Open-ILS/src/support-scripts/overdrive-api-checker.pl --account <account_id> --token <basic_token>

    To send a request to a specific API endpoint:

    Open-ILS/src/support-scripts/overdrive-api-checker.pl --account <account_id> --token <basic_token>
    --endpoint <endpoint> --content <content>

    To test OverDrive API authentication for a specific patron:

    Open-ILS/src/support-scripts/overdrive-api-checker.pl --account <account_id> --token <basic_token>
    --patron-auth --barcode <barcode> --password <password>
    --websiteid <websiteid> --authorizationname <authorizationname>

Signed-off-by: Jeff Davis <jdavis@sitka.bclibraries.ca>
Signed-off-by: Martha Driscoll <driscoll@noblenet.org>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>

Open-ILS/src/support-scripts/overdrive-api-checker.pl [new file with mode: 0755]

diff --git a/Open-ILS/src/support-scripts/overdrive-api-checker.pl b/Open-ILS/src/support-scripts/overdrive-api-checker.pl
new file mode 100755 (executable)
index 0000000..32a63ab
--- /dev/null
@@ -0,0 +1,190 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+use LWP::UserAgent;
+use HTTP::Request;
+use JSON;
+use Getopt::Long;
+use MIME::Base64;
+use Data::Dumper;
+
+my $account_id;
+my ($basic_token, $get_token, $client_key, $client_secret);
+my ($api_endpoint, $content);
+my $oauth_endpoint = 'https://oauth.overdrive.com/token';
+my $oauth_only; 
+my ($patron_auth, $barcode, $password, $websiteid, $authorizationname); 
+my ($verbose, $help);
+my ($authtoken, $auth_content);
+
+GetOptions(
+    'account=s'        => \$account_id,     # OverDrive API account ID
+    'get-token'        => \$get_token,      # generate basic client token
+    'key=s'            => \$client_key,     # OverDrive client key
+    'secret=s'         => \$client_secret,  # OverDrive client secret
+    'token=s'          => \$basic_token,    # basic client token for OAuth requests
+    'endpoint=s'       => \$api_endpoint,   # main API endpoint
+    'content=s'        => \$content,        # main request content (optional)
+    'oauth-endpoint=s' => \$oauth_endpoint, # API endpoint for OAuth requests
+    'oauth-only'       => \$oauth_only,     # only attempt OAuth request, then stop
+    'patron-auth'      => \$patron_auth,    # perform patron authentication
+    'barcode=s'        => \$barcode,        # patron barcode
+    'password=s'       => \$password,        # patron password
+    'websiteid=s'      => \$websiteid,      # OverDrive website ID
+    'authorizationname=s' => \$authorizationname, # OverDrive ILS name
+    'verbose'          => \$verbose,        # verbose output
+    'help'             => \$help            # show help message and exit
+);
+
+if ($help) {
+    print <<"HELP";
+USAGE:
+    $0 --get-token --key <client-key> --secret <client-secret>
+    $0 --account <account_id> --token <basic_token> [ --endpoint https://api.overdrive.com/v1/libraries/1234 [ --content <content> ] ]
+    $0 --account <account_id> --token <basic_token> --oauth-only
+    $0 --account <account_id> --token <basic_token> --patron-auth [ --endpoint https://oauth-patron.overdrive.com/patrontoken ] --barcode <barcode> [ --password <password> ] --websiteid <websiteid> --authorizationname <authorizationname>
+
+OPTIONS:
+    --get-token
+        Generate OverDrive API basic token.
+    --key
+        Client key supplied by OverDrive.  Required with --get-token.
+    --secret
+        Client secret supplied by OverDrive.  Required with --get-token.
+    --token
+        Your OverDrive API basic token (clientKey:clientSecret, Base64-encoded).
+        Required unless using --get-token.
+    --account
+        Your OverDrive API account ID (e.g. 1234).  Not required for generating
+        a basic token; required for everything else.
+    --oauth-endpoint
+        OverDrive API endpoint for OAuth token requests.
+        Default: https://oauth.overdrive.com/token.
+    --endpoint
+        OverDrive API endpoint that you wish to test.
+        Default: https://api.overdrive.com/v1/libraries/<account>
+    --content
+        JSON content of main API request.  Required only if you have specified
+        an endpoint that expects JSON message content.
+    --oauth-only
+        Only request an OAuth token; do not attempt further API requests.
+    --patron-auth
+        Submit a patron authentication request.
+    --barcode
+        Patron barcode.  Required with --patron-auth.
+    --password
+        Patron password.  Required with --patron-auth if your library requires
+        password for patron authentication.
+    --websiteid
+        Website ID supplied by OverDrive.  Required with --patron-auth.
+    --authorizationname
+        ILS name supplied by OverDrive.  Required with --patron-auth.
+    --verbose
+        Print full HTTP requests and responses.
+    --help
+        Print this help message.
+
+EXAMPLES:
+
+    To generate your basic token, given a client key and client secret supplied
+    by OverDrive:
+
+    $0 --get-token --key <client-key> --secret <client-secret>
+
+    To send a basic API request (this is useful for validating your client
+    credentials and determining whether the OverDrive API is currently
+    available):
+
+    $0 --account <account_id> --token <basic_token>
+
+    To send a request to a specific API endpoint:
+
+    $0 --account <account_id> --token <basic_token> \
+    --endpoint <endpoint> --content <content>
+
+    To test OverDrive API authentication for a specific patron:
+
+    $0 --account <account_id> --token <basic_token> \
+    --patron-auth --barcode <barcode> --password <password> \
+    --websiteid <websiteid> --authorizationname <authorizationname>
+
+HELP
+    exit;
+}
+
+if ($get_token) {
+    die "No client key provided" unless ($client_key);
+    die "No client secret provided" unless ($client_secret);
+    $basic_token = encode_base64("$client_key:$client_secret");
+    print "Your basic token is: $basic_token\n";
+    exit unless ($api_endpoint || $oauth_only || $patron_auth);
+}
+
+die "No basic token provided" unless ($basic_token);
+die "No account ID provided" unless ($account_id);
+
+my $ua = new LWP::UserAgent;
+
+# First, we use our basic token to request an access (bearer) token from the OAuth endpoint.
+
+if (!$patron_auth) {
+
+    # construct the HTTP request
+    my $auth_req = HTTP::Request->new( POST => $oauth_endpoint );
+    $auth_req->header('Authorization' => "Basic $basic_token");
+    $auth_req->content_type('application/x-www-form-urlencoded;charset=UTF-8');
+    $auth_req->content('grant_type=client_credentials');
+
+    # send the request and handle the response
+    my $auth_resp = $ua->request($auth_req);
+    if (!$auth_resp->is_success) {
+        die "Error on auth request: " . $auth_resp->status_line . "\n";
+    }
+    $auth_content = decode_json($auth_resp->decoded_content);
+    $authtoken = $auth_content->{access_token};
+
+    print "$authtoken\n" if ($oauth_only || $verbose);
+    exit if ($oauth_only);
+    sleep 1;
+}
+
+# Now that we have our bearer token, we can make our main API request.
+if (!$api_endpoint) {
+    if ($patron_auth) {
+        $api_endpoint = "https://oauth-patron.overdrive.com/patrontoken";
+    } else {
+        $api_endpoint = "https://api.overdrive.com/v1/libraries/$account_id";
+    }
+}
+
+# Determine method and initialize HTTP request object
+my $method = ($patron_auth) ? 'POST' : 'GET';
+my $api_req = HTTP::Request->new( $method => $api_endpoint );
+
+# Flesh out our request.
+if ($patron_auth) {
+    $api_req->header('Authorization' => "Basic $basic_token");
+    $api_req->content_type("application/x-www-form-urlencoded;charset=UTF-8");
+    if ($password) {
+        $api_req->content("grant_type=password&username=$barcode&password=$password&scope=websiteid:$websiteid authorizationname:$authorizationname");
+    } else {
+        $api_req->content("grant_type=password&username=$barcode&password=1234&password_required=false&scope=websiteid:$websiteid authorizationname:$authorizationname");
+    }
+} else {
+    $api_req->header('Authorization' => "bearer $authtoken");
+    $api_req->content_type('application/json');
+    $api_req->content($content) if ($content);
+}
+print Dumper $api_req if ($verbose);
+
+# Send API request and handle response.
+my $api_resp = $ua->request($api_req);
+if (!$api_resp->is_success) {
+    print "Error on API request: " . $api_resp->status_line . "\n";
+    print Dumper $api_resp if ($verbose);
+    die;
+}
+print "Success: " . $api_resp->status_line . "\n";
+print $api_resp->decoded_content . "\n" if ($verbose);
+