generic OAuth1 completed. With dropbox demo

Signed-off-by: Luca Fulchir <luca@fulchir.it>
parent 2b3e49fb
......@@ -35,6 +35,14 @@ main {
[RequestToken (info) (token) {
scope (error_handler) {
install (wrong_answer =>
println@Console("OAuth1:wrong answer from server")();
throw (OAuth1_error),
Hmac_fault =>
println@Console("OAuth1:couldn't generate hmac")();
throw (OAuth1_error)
);
http_data.URI = info.location_request;
toUpperCase@StringUtils (info.method) (http_data.method);
info.method = http_data.method;
......@@ -51,18 +59,19 @@ main {
getPair@OAuth1Data(tmp)(token.token);
tmp.search = "oauth_token_secret";
getPair@OAuth1Data(tmp)(token.token_secret)
}
}]{nullProcess}
[getReferral (info) (output) {
http_data.URI = info.location_authorize;
http_data.headers[0].name = "userAgent";
http_data.headers[0].value = "Jolie-OAuth";
http_data.query[0].name = "oauth_token";
http_data.query[0].value = info.token;
http_data.query[1].name = "oauth_callback";
if (is_defined(info.callback)) {
http_data.query[1].name = "oauth_callback";
http_data.query[1].value = info.callback
} else {
// out of band -- required
http_data.query[1].value = "oob"
};
http_data.method = "GET";
......@@ -71,12 +80,16 @@ main {
}] {nullProcess}
[getAccess (info) (output) {
if (!is_defined(info.token)) {
println@Console("OAuth1: token missing")();
throw (OAuth1_error)
};
http_data.URI = info.location_access;
http_data.headers[0].name = "userAgent";
http_data.headers[0].value = "Jolie-OAuth";
http_data.method = "POST";
http_data.headers[1].name = "Authorization";
DataAuthenticate@OAuth1Data (info) (http_data.headers[1].value);
DataAccess@OAuth1Data (info) (http_data.headers[1].value);
sendRequest@HTTP(http_data) (answer);
......
......@@ -29,10 +29,12 @@ type OAuth1Info:void {
.location_access :string
.method :string
.callback? :string
.realm? :string
.consumer_key :string
.secret? :string
.token? :string
.token_secret? :string
.verifier? :string
// HTTP additional user-specified parameters
.headers? :OAuth1Pair
.query? :OAuth1Pair
......@@ -55,7 +57,7 @@ type OAuth1_pairSearch:void {
interface OAuth1DataInterface {
RequestResponse:
DataRequestToken (OAuth1Info) (string),
DataAuthenticate (OAuth1Info) (string),
DataAccess (OAuth1Info) (string),
parseAnswer (string) (OAuth1_parsed) throws wrong_answer,
getPair (OAuth1_pairSearch) (string) throws not_found
}
......
......@@ -21,10 +21,9 @@
include "security_utils.iol"
include "time.iol"
include "OAuth1Data.iol"
include "string_utils.iol"
include "OAuth1Data.iol"
include "jolie/net/utils/Hmac.iol"
include "console.iol"
include "jolie/net/utils/HTTP.iol"
inputPort OAuth1Data{
......@@ -38,10 +37,6 @@ main {
[DataRequestToken (info) (postString)
{
scope (error_handler) {
install( Hmac_fault =>
println@Console("HmacError") ();
throw(Hmac_fault)
);
// getCurrentTimeMillis is a temporary interface, but there's
// nothing better :(
getCurrentTimeMillis@Time(void)(tmp_timestamp);
......@@ -55,10 +50,15 @@ scope (error_handler) {
toSort.item[2] = "oauth_nonce=" + oauth_nonce;
toSort.item[3] = "oauth_version=1.0";
toSort.item[4] = "oauth_consumer_key=" + info.consumer_key;
count = 4;
if (is_defined(info.callback)) {
callback="oob";
toEncode.encoding = "UTF8";
toEncode = info.callback;
URLencode@HTTP (toEncode) (callback);
toSort.item[5] = "oauth_callback=" + callback;
count = #toSort.item - 1;
if (is_defined(info.realm)) {
count = count + 1;
toSort.item[count] = "oauth_callback=" + info.callback
toSort.item[count] = "oauth_realm=" + info.realm
};
sort@StringUtils (toSort) (sorted);
......@@ -85,21 +85,26 @@ scope (error_handler) {
toEncode = tmpSignature;
URLencode@HTTP (toEncode) (signature);
postString = "OAuth " +
postString = "OAuth " +
"oauth_callback=\"" + callback + "\"," +
"oauth_consumer_key=\"" + info.consumer_key + "\"," +
"oauth_nonce=\"" + oauth_nonce + "\"," +
"oauth_signature_method=\"HMAC-SHA1\"," +
"oauth_timestamp=\"" + tmp_timestamp + "\"," +
"oauth_nonce=\"" + oauth_nonce + "\"," +
"oauth_version=\"1.0\"," +
"oauth_signature=\"" + signature + "\"";
if ( is_defined(info.callback))
postString = postString +
",oauth_callback=\"" + info.callback + "\""
if (is_defined(info.realm)) {
postString = postString + ",oauth_realm=\"" + info.realm + "\""
}
}
}]{nullProcess}
[DataAuthenticate (info) (postString)
[DataAccess (info) (postString)
{
if (!is_defined(info.token)) {
throw(OAuth1_access_not_enough_info)
};
// getCurrentTimeMillis is a temporary interface, but there's
// nothing better :(
getCurrentTimeMillis@Time(void)(tmp_timestamp);
......@@ -147,6 +152,9 @@ scope (error_handler) {
[parseAnswer (answer) (token) {
scope (parsing) {
install ( StringIndexOutOfBoundsException =>
throw (wrong_answer)
);
answer.regex = "&";
split@StringUtils(answer)(strings);
for (i = 0, i < #strings.result, i++) {
......
......@@ -22,17 +22,16 @@
include "OAuth2.iol"
include "string_utils.iol"
include "console.iol"
//include "jolie/net/utils/HTTP.iol"
inputPort OAuth2 {
Location: "local"
Interfaces: OAuth2Interface
}
execution { concurrent}
execution {concurrent}
main {
[Auth (info) (answer) {
Auth (info) (answer) {
http_data.URI = info.location_authorize;
toUpperCase@StringUtils (info.method) (http_data.method);
info.method = http_data.method;
......@@ -61,9 +60,9 @@ scope (error_handler) {
buildURI@HTTP(http_data) (answer)
}
}]{nullProcess}
};
[Access (info) (newInfo) {
Access (info) (newInfo) {
newInfo << info;
http_data.URI = info.location_access;
toUpperCase@StringUtils (info.method) (http_data.method);
......@@ -80,7 +79,13 @@ scope (error_handler) {
throw(OAuth2_error),
send_error =>
println@Console("could not send HTTP request")();
throw(OAuth2_error)
throw(OAuth2_error),
oauth2_missing_data =>
println@Console("missing data for OAuth2 access")();
throw(OAuth2_error),
cannot_translate =>
println@Console("didn't receive proper json")();
throw (Oauth2_error)
);
DataAccess@OAuth2Data (info) (data_query);
http_data.content << data_query.pair;
......@@ -123,10 +128,9 @@ scope (error_handler) {
};
newInfo.json = answer_json
}
}]{nullProcess}
};
[Refresh (info) (newInfo)
{
Refresh (info) (newInfo) {
newInfo << info;
http_data.URI = info.location_access;
toUpperCase@StringUtils (info.method) (http_data.method);
......@@ -144,9 +148,12 @@ scope (error_handler) {
send_error =>
println@Console("could not send HTTP request")();
throw(OAuth2_error),
refresh_token =>
println@Console("can't refresh without a refresh_token")();
throw(OAuth2_error)
oauth2_missing_data =>
println@Console("can't refresh without needed data")();
throw(OAuth2_error),
cannot_translate =>
println@Console("didn't receive proper json")();
throw (Oauth2_error)
);
DataRefresh@OAuth2Data (info) (data_query);
for (count=#newInfo.query, count < (#newInfo.query + #data_query.pair),
......@@ -181,7 +188,7 @@ scope (error_handler) {
};
newInfo.json = answer_json
}
}]{nullProcess}
}
}
......@@ -45,15 +45,11 @@ type OAuth2Info:void {
.query? :OAuth2Pair
}
type OAuth2_pair:void {
.name :string
.value :string
}
type OAuth2_Search:void {
.search :string
.pair* :OAuth2_pair
.pair* :OAuth2Pair
}
type OAuth2_SearchRes:string {
.found :bool
}
......
......@@ -19,12 +19,8 @@
* For details about the authors of this software, see the AUTHORS file. *
***************************************************************************/
include "security_utils.iol"
include "time.iol"
include "OAuth2Data.iol"
include "string_utils.iol"
include "jolie/net/utils/Hmac.iol"
include "console.iol"
inputPort OAuth2Data{
Location: "local"
......@@ -34,8 +30,7 @@ inputPort OAuth2Data{
execution {concurrent}
main {
[DataAuth (info) (data)
{
DataAuth (info) (data) {
data.pair[0].name = "client_id";
data.pair[0].value = info.client_id;
data.pair[1].name = "response_type";
......@@ -56,10 +51,12 @@ main {
data.pair[count].value = info.state;
count++
}
}]{nullProcess}
};
[DataAccess (info) (data)
{
DataAccess (info) (data) {
if (!is_defined(info.code) || !is_defined(info.client_secret)) {
throw (oauth2_missing_data)
};
data.pair[0].name = "client_id";
data.pair[0].value = info.client_id;
data.pair[1].name = "grant_type";
......@@ -79,12 +76,11 @@ main {
data.pair[count].value = info.scope;
count++
}
}]{nullProcess}
};
[DataRefresh (info) (data)
{
if (!is_defined(info.refresh_token)) {
throw (refresh_token)
DataRefresh (info) (data) {
if (!is_defined(info.refresh_token) || !is_defined(info.client_secret)) {
throw (oauth2_missing_data)
};
data.pair[0].name = "client_id";
data.pair[0].value = info.client_id;
......@@ -98,9 +94,9 @@ main {
data.pair[4].name = "scope";
data.pair[4].value = info.scope
}
}]{nullProcess}
};
[getPair (pairSearch) (result) {
getPair (pairSearch) (result) {
result="";
result.found = false;
length@StringUtils(pairSearch.search)(search_length);
......@@ -116,8 +112,7 @@ main {
result.found = true
}
}
}]{nullProcess}
}
}
......@@ -4,17 +4,34 @@ include "OAuth1.iol"
include "security_utils.iol"
include "time.iol"
include "string_utils.iol"
type accessAnswer:void {
.uid :int
.oauth_token :string
.oauth_verifier? :string
}
interface OAuth1_HTTP {
RequestResponse:
access(accessAnswer)(string)
}
inputPort HTTP_Get {
Location: "socket://localhost:8011/"
Protocol: http
Interfaces: OAuth1_HTTP
}
main
{
// data needed for the connection: where to connect, how and who we are
data.location_request = "https://api.dropbox.com/1/oauth/request_token";
data.location_authorize = "https://www.dropbox.com/1/oauth/authorize";
data.location_access = "https://api.dropbox.com/1/oauth/access_token";
data.method = "post";
data.method = "POST";
data.consumer_key = "27250pnzil7tmhx";
data.secret = "6yj3c6mjbdixm6i";
data.callback = "";
data.callback = "http://localhost:8011/access";
// send the message
RequestToken@OAuth1 (data) (answer);
......@@ -23,10 +40,17 @@ main
println@Console ("token_secret: " + answer.token_secret)();
getReferral@OAuth1 (answer) (referr);
println@Console ("auth this app with (15 seconds): " + referr)();
sleep@Time(15000)();
println@Console("\nauthenticate this app with:\n" + referr)();
println@Console("Now waiting for http refer")();
[access (access) (response) {
if (is_defined(access.oauth_verifier)) {
data.verifier = access.oauth_verifier
};
response = "ok"
}]{
undef(data.callback);
getAccess@OAuth1 (answer) (tokens);
// use these to sign whatever data in your api calls:
......@@ -35,6 +59,6 @@ main
println@Console(tokens.pair[i].name + " = " +
tokens.pair[i].value)()
}
}
}
include "console.iol"
include "OAuth2.iol"
include "security_utils.iol"
include "time.iol"
include "string_utils.iol"
//execution { concurrent }
type codeRequest:void {
.code? :string
......@@ -53,8 +51,7 @@ main
if (!is_defined(codeRequest.code)) {
println@Console("We got a redirect, no code included")();
out = ERR
};
if (is_defined(data.state)) {
} else if (is_defined(data.state)) {
if (!is_defined(codeRequest.state)) {
println@Console("We got a redirect, but it wasn't ours")();
out = ERR
......@@ -84,6 +81,7 @@ main
};
data.code = codeRequest.code;
data.method = "POST";
undef(data.redirect_uri);
// next step in Auth2 authentication.
Access@OAuth2 (data) (answer);
println@Console("token:" + answer.access_token)();
......@@ -92,6 +90,5 @@ main
println@Console("refresh_token:" + answer.refresh_token)()
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment