• Topic
  • Discussion
  • VOS.VirtOAuth(Last) -- DAVWikiAdmin? , 2017-06-29 07:38:49 Edit WebDAV System Administrator 2017-06-29 07:38:49

    OAuth Implementation in OpenLink Data Spaces

    OAuth tokens must be generated for each user account, for each ODS application, via ODS -> Settings -> OAuth Keys. This UI provides a list of all applications to which the logged-in user has access, i.e., of which the user is a member or owner. To enable access with OAuth, the user simply selects the desired application instance from the list, and clicks the 'generate keys' button. The generated Consumer Key and Secret will be associated with the given ODS user account & application instance.

    Once a consumer token is available, the sequence below must be executed in order to establish an authorized session:

    1. client uses request_token to get a token/secret pair for establishing session using consumer token
    2. client asks OAuth server to authorize the token from step-1
    3. using authorized token from step-1 client asks OAuth server for authentication token.
    4. with authentication token from step-3, clients can access instance data associated with the consumer token from step-1.

    Sample OAuth Client

    To demonstrate the Virtuoso implementation of OAuth, we have written this sample client, in Virtuoso/PL.

        declare consumer_key, consumer_secret, oauth_token, oauth_secret, signature, timest, nonce varchar;
        declare srv, res, signature_base, ret_url, url, tmp, sid varchar;
        declare meth, pars any;
        consumer_key := {?'key'};
        srv := sprintf ('http://localhost:%s/OAuth/', server_http_port ());
        sid := null;
        res := '';
        sid :=  {?'sid'};
        if (sid = '') 
          sid := null;    
            -- if selected token is not same as one from the session we need to get new authentication token
            if (consumer_key <> OAUTH..get_consumer_key (sid))
            OAUTH..session_terminate (sid);
                sid := null;
        meth := get_keyword ('meth', params, 'weblog.post.new');;
        pars := get_keyword ('pars', params, 'inst_id=15&title=testing&description=Some test post');;
        if ({?'rt'} is not null and sid is null) -- request new token for the session
        url := srv||'request_token'; 
        url := OAUTH..sign_request ('GET', url, '', consumer_key, sid);
            res := http_get (url);
        sid := OAUTH..parse_response (sid, consumer_key, res);
        OAUTH..set_session_data (sid, params);
        ret_url := sprintf ('http://localhost:%s/oauth/oauth_client.vsp?ready=%U', server_http_port (), sid);
        -- call authorize 
            url := sprintf ('%sauthorize?oauth_token=%U&oauth_callback=%U', srv, OAUTH..get_auth_token (sid), ret_url); 
        http_status_set (301);
            http_header (sprintf ('Location: %s\r\n', url));
        else if ({?'ready'} is not null) -- get access token
        -- we go here when token above is authorized
            sid := {?'ready'};
        url := srv||'access_token'; 
        consumer_key := OAUTH..get_consumer_key (sid);
        url := OAUTH..sign_request ('GET', url, '', consumer_key, sid);
            res := http_get (url);
        sid := OAUTH..parse_response (sid, consumer_key, res);
        if (sid is not null) -- access token is ready, and we can call API
            -- here we are ready to call service
        if ({?'rt'} is null)
                tmp := OAUTH..get_session_data (sid);
                pars := get_keyword ('pars', tmp, pars);
            meth := get_keyword ('meth', tmp, meth);
        url := sprintf ('http://localhost:%s/ods/api/%s', server_http_port (), meth);
        tmp := split_and_decode (pars);
        params := '';
        for (declare i,l int, l:=length (tmp); i < l; i := i + 2)
             params := params || sprintf ('%U=%U&', tmp[i], tmp[i+1]);      
        --params := sprintf ('inst_id=%d&description=%U&title=%U', 15, 'Some test post', 'testing');
        consumer_key := OAUTH..get_consumer_key (sid);
        url := OAUTH..sign_request ('GET', url, params, consumer_key, sid);
            res := http_get (url);
            --dbg_obj_print (res); 
        <head><title>OAuth Client</title></head>
        <h1>OAuth client for ODS Controllers</h1>
        <form method="POST" action="oauth_client.vsp">
        <input type="hidden" name="sid" value="<?V sid ?>"/>
        APPLICATION : <br /> <select name="key">
        <?vsp for select a_name, a_key from OAUTH..APP_REG do { ?>
            <option value="<?V a_key ?>" <?vsp if (consumer_key = a_key) http ('selected'); ?>><?V a_name ?></option>
        <?vsp } ?>
        if (sid is not null) http (sprintf (' TOKEN: %s', OAUTH..get_auth_token (sid)));    
        <br />
        ODS API: <br /><input type="text" name="meth" value="<?V meth ?>" size=50/> <br />
        PARAMETERS: <br /> <textarea name="pars" rows="5" cols="50"><?V pars ?></textarea> <br />
            <input type="submit" value="Execute" name="rt"/><br />  
        <pre><?V res ?></pre>

    Sample OAuth Session

    The following shows a sample session, using the above Virtuoso/PL OAuth client.

    GET /OAuth/request_token?oauth_consumer_key=50082d0fb861b0e6e67d5d986b8
    757LBHcmqVJ6obMhNX5hKA%3D HTTP/1.1
    Host: localhost:6666
    HTTP/1.1 200 Ok
    Content-Length: NNN

    GET /OAuth/authorize?oauth_token=86da75079d3aee0fab57a36fcffbf900768e4d
    ady%3D00c874b2fab2f6424008b5064fe83e88 HTTP/1.1
    Host: localhost:6666
    HTTP/1.1 301 Moved
    Location: /ods/oauth_authorize.vspx?....

    GET /OAuth/access_token?oauth_consumer_key=50082d0fb861b0e6e67d5d986b83
    g9o%3D HTTP/1.1
    Host: localhost:6666
    HTTP/1.1 200 Ok
    Content-Length: NNN

    GET /ods/api/weblog.post.new?description=Some%20test%20post&inst_id=15&
    on=1.0&title=testing&oauth_signature=oocIyr6kgoEQkC3WVwzvl6w62W4%3D HTT
    Host: localhost:6666
    HTTP/1.1 200 Ok
    Content-Length: NNN

    Additional Information

    General OAuth Information

    Virtuoso- and OpenLink-specific OAuth Information