initial oauth2 code

Signed-off-by: Luca Fulchir <luca@fulchir.it>
parent 8d69b781
OAUTH2:
AuthRequest:
send:
-response_type (required = code)
-client_id (required)
-redirect_uri (optional)
-scope (optional)
-state (optional)
get:
-code (required)
-scope (optional if)
-state (required if)
error:
-error
-blablabla
AccessRequest:
send:
-grant_type (required)
-code (required)
-redirect_uri (required)
-client_id (required)
get:
-access_token (required)
-token_type (required)
-expires_in (recommended)
-refresh_token (optional)
-scope (optional if)
error:
-error
-bla-bla
-------------------------------
AuthRequest:
-response_type (required = token)
-client_it (required)
-redirect_uri (optional)
-scope (optional)
-state (recommended)
(redirect)
AccessResponse:
-access_token (required)
-token_type (required)
-expires_in (recommended)
-scope (optional if)
-state (required if)
/* *************************************************************************
* Copyright (C) 2013 by Luca Fulchir <luca@fulchir.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
* For details about the authors of this software, see the AUTHORS file. *
***************************************************************************/
include "OAuth2Data.iol"
interface OAuth2Interface {
RequestResponse:
RequestToken (OAuth2Info) (OAuth2Info) throws wrong_answer,
getReferral (OAuth2Info) (string),
getAccess (OAuth2Info) (OAuth2_parsed)
}
outputPort OAuth2 {
Interfaces: OAuth2Interface
}
embedded {
Jolie:
"OAuth2.ol" in OAuth2
}
/* *************************************************************************
* Copyright (C) 2013 by Luca Fulchir <luca@fulchir.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
* For details about the authors of this software, see the AUTHORS file. *
***************************************************************************/
include "OAuth2.iol"
include "jolie/net/utils/HTTP.iol"
include "string_utils.iol"
include "console.iol"
inputPort OAuth2 {
Location: "local"
Interfaces: OAuth2Interface
}
execution { concurrent}
main {
[AuthRequest (info) (newInfo) {
newInfo << info;
http_data.URI = info.location_authorize;
toUpperCase@StringUtils (info.method) (http_data.method);
info.method = http_data.method;
newInfo.method = info.method;
http_data.headers[0].name = "userAgent";
http_data.headers[0].value = "Jolie-OAuth2";
scope (error_handler) {
install(not_found =>
println@Console("error on request") ();
throw(OAuth2_error)
state_mismatch =>
println@Console("wrong state in reply") ();
throw(OAuth2_error)
send_error =>
println@Console("could not send HTTP request")();
throw(OAuth2_error)
);
//make HTTP request
DataAuthRequest@OAuth2Data (info) (data_query);
http_data.query << newInfo.query;
for (count=#newInfo.query, count < (#newInfo.query + #data_query),
count++) {
http_data.query[count] << data_query[count - #newInfo.query]
};
sendRequest@HTTP(http_data) (codes);
// search for errors
search.pair = codes;
search.search = "code";
getPair@OAuth2Data (search)(res);
newInfo.code = res;
if (info.hasChildren("state")) {
search.search = "state";
getPair@OAuth2Data (search)(res);
//check for equality... really fast this way, uh?
length@StringUtils(res)(ln1);
length@StringUtils(info.state)(ln2);
if (ln1 != ln2) {
throw(state_mismatch)
};
res.startswith=info.state;
startsWith(res)(strTest);
if (!strTest) {
throw(state_mismatch)
}
}
}
}]{nullProcess}
[AccessRequest (info) (newInfo) {
newInfo << info;
http_data.URI = info.location_access;
toUpperCase@StringUtils (info.method) (http_data.method);
info.method = http_data.method;
newInfo.method = info.method;
http_data.headers[0].name = "userAgent";
http_data.headers[0].value = "Jolie-OAuth2";
scope (error_handler) {
install(not_found =>
println@Console("error on request") ();
throw(OAuth2_error)
state_mismatch =>
println@Console("wrong state in reply") ();
throw(OAuth2_error)
send_error =>
println@Console("could not send HTTP request")();
throw(OAuth2_error)
);
AccessRequest@OAuth2Data (info) (data_query);
for (count=#newInfo.query, count < (#newInfo.query + #data_query),
count++) {
http_data.query[count] << data_query[count - #newInfo.query]
};
sendRequest@HTTP(http_data) (answer);
// search for errors
search.pair = answer;
search.search = "access_token";
getPair@OAuth2Data (search)(newInfo.access_token);
newInfo.code = res;
if (info.hasChildren("state")) {
search.search = "state";
getPair@OAuth2Data (search)(res);
//check for equality... really fast this way, uh?
length@StringUtils(res)(ln1);
length@StringUtils(info.state)(ln2);
if (ln1 != ln2) {
throw(state_mismatch)
};
res.startswith=info.state;
startsWith(res)(strTest);
if (!strTest) {
throw(state_mismatch)
}
}
}]{nullProcess}
[RequestToken (info) (token) {
http_data.URI = info.location_request;
toUpperCase@StringUtils (info.method) (http_data.method);
info.method = http_data.method;
http_data.headers[0].name = "userAgent";
http_data.headers[0].value = "Jolie-OAuth";
http_data.headers[1].name = "Authorization";
DataRequestToken@OAuth2Data (info) (http_data.headers[1].value);
sendRequest@HTTP(http_data) (answer);
token << info;
parseAnswer@OAuth2Data(answer) (tmp);
tmp.search = "oauth_token";
getPair@OAuth2Data(tmp)(token.token);
tmp.search = "oauth_token_secret";
getPair@OAuth2Data(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;
if (is_defined(info.callback)) {
http_data.query[1].name = "oauth_callback";
http_data.query[1].value = info.callback
};
http_data.method = "GET";
buildURI@HTTP (http_data) (output)
}] {nullProcess}
[getAccess (info) (output) {
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@OAuth2Data (info) (http_data.headers[1].value);
sendRequest@HTTP(http_data) (answer);
parseAnswer@OAuth2Data (answer) (output)
}] {nullProcess}
}
/* *************************************************************************
* Copyright (C) 2013 by Luca Fulchir <luca@fulchir.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
* For details about the authors of this software, see the AUTHORS file. *
***************************************************************************/
type OAuth2Pair:void {
.name :string
.value :string
}
type OAuth2Info:void {
.location_authorize :string
.location_access :string
.method :string
.client_id :string
.code? :string
.redirect_uri? :string
.scope? :string
.state? :string
.access_token? :string
.token_type? :string
.refresh_token? :string
.expires? :int
// HTTP additional user-specified parameters
.headers? :OAuth2Pair
.query? :OAuth2Pair
}
type OAuth2_pair:void {
.name :string
.value :string
}
type OAuth2_pairSearch:void {
.search :string
.pair* :OAuth2_pair
}
interface OAuth2DataInterface {
RequestResponse:
DataAuthRequest (OAuth2Info) (HTTPpair),
DataRequestToken (OAuth2Info) (string),
DataAuthenticate (OAuth2Info) (string),
parseAnswer (string) (OAuth2_parsed) throws wrong_answer,
getPair (OAuth2_pairSearch) (string) throws not_found
}
outputPort OAuth2Data {
Interfaces: OAuth2DataInterface
}
embedded {
Jolie:
"OAuth2Data.ol" in OAuth2Data
}
/* *************************************************************************
* Copyright (C) 2013 by Luca Fulchir <luca@fulchir.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
* 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"
include "jolie/net/utils/HTTP.iol"
inputPort OAuth2Data{
Location: "local"
Interfaces: OAuth2DataInterface
}
execution {concurrent}
main {
[DataAuthRequest (info) (data)
{
data[0].name = "client_id";
data[0].value = info.client_id;
data[0].format= "application/x-www-form-urlencoded";
data[1].name = "response_type";
data[1].value = "code";
data[1].format= "application/x-www-form-urlencoded";
count = #data;
if (info.hasChildren("redirect_uri")) {
data[count].name = "redirect_uri";
data[count].value = info.redirect_uri;
data[count].format= "application/x-www-form-urlencoded";
count++
};
if (info.hasChildren("scope")) {
data[count].name = "scope";
data[count].value = info.scope;
data[count].format= "application/x-www-form-urlencoded";
count++
};
if (info.hasChildren("state")) {
data[count].name = "state";
data[count].value = info.state;
data[count].format= "application/x-www-form-urlencoded";
count++
}
}]{nullProcess)
[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);
tmp_timestamp = tmp_timestamp / 1000;
// a little too much as a nonce, but it's easier this way :p
createSecureToken@SecurityUtils(void)(oauth_nonce);
toSort.item[0] = "oauth_signature_method=HMAC-SHA1";
toSort.item[1] = "oauth_timestamp=" + tmp_timestamp;
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)) {
count = count + 1;
toSort.item[count] = "oauth_callback=" + info.callback
};
sort@StringUtils (toSort) (sorted);
toEncode.encoding = "UTF8";
toEncode = info.location_request;
URLencode@HTTP (toEncode) (encodedLocation);
toHash.secret = "";
if (is_defined(info.secret))
toHash.secret = info.secret;
toHash.secret = toHash.secret + "&";
toHash.data = info.method + "&" + encodedLocation + "&";
tmp = "";
for (i = 0, i < count, i++) {
tmp = tmp + sorted.item[i] + "&"
};
tmp = tmp + sorted.item[count];
toEncode = tmp;
URLencode@HTTP (toEncode) (encodedParams);
toHash.data = toHash.data + encodedParams;
sha1@Hmac (toHash) (tmpSignature);
toEncode = tmpSignature;
URLencode@HTTP (toEncode) (signature);
postString = "OAuth " +
"oauth_consumer_key=\"" + info.consumer_key + "\"," +
"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 + "\""
}
}]{nullProcess}
[DataAuthenticate (info) (postString)
{
// getCurrentTimeMillis is a temporary interface, but there's
// nothing better :(
getCurrentTimeMillis@Time(void)(tmp_timestamp);
tmp_timestamp = tmp_timestamp / 1000;
// a little too much as a nonce, but it's easier this way :p
createSecureToken@SecurityUtils(void)(oauth_nonce);
toSort.item[0] = "oauth_signature_method=HMAC-SHA1";
toSort.item[1] = "oauth_timestamp=" + tmp_timestamp;
toSort.item[2] = "oauth_nonce=" + oauth_nonce;
toSort.item[3] = "oauth_version=1.0";
toSort.item[4] = "oauth_consumer_key=" + info.consumer_key;
toSort.item[5] = "oauth_token=" + info.token;
sort@StringUtils (toSort) (sorted);
toEncode.encoding = "UTF8";
toEncode = info.location_access;
URLencode@HTTP (toEncode) (encodedLocation);
tmp = "";
for (i = 0, i < (#toSort.item - 1), i++) {
tmp = tmp + sorted.item[i] + "&"
};
tmp = tmp + sorted.item[#sorted.item - 1];
toEncode = tmp;
URLencode@HTTP (toEncode) (encodedParams);
toHash.secret = info.secret + "&" + info.token_secret;
toHash.data = info.method + "&" + encodedLocation + "&" + encodedParams;
sha1@Hmac (toHash) (tmpSignature);
toEncode = tmpSignature;
URLencode@HTTP (toEncode) (signature);
postString = "OAuth " +
"oauth_consumer_key=\"" + info.consumer_key + "\"," +
"oauth_signature_method=\"HMAC-SHA1\"," +
"oauth_timestamp=\"" + tmp_timestamp + "\"," +
"oauth_nonce=\"" + oauth_nonce + "\"," +
"oauth_version=\"1.0\"," +
"oauth_token=\"" + info.token + "\"," +
"oauth_signature=\"" + signature + "\""
}]{nullProcess}
[parseAnswer (answer) (token) {
scope (parsing) {
answer.regex = "&";
split@StringUtils(answer)(strings);
for (i = 0, i < #strings.result, i++) {
tmp = strings.result[i];
tmp.word = "=";
indexOf@StringUtils(tmp) (index);
//TODO: what if not found?
undef(tmp.word);
length@StringUtils(tmp) (length);
tmp.begin = 0;
tmp.end = index;
substring@StringUtils(tmp) (token.pair[i].name);
tmp.begin = index + 1;
tmp.end = length;
substring@StringUtils(tmp) (token.pair[i].value);
undef(tmp.begin);
undef(tmp.end)
}
}
}]{nullProcess}
[getPair (pairSearch) (result) {
length@StringUtils(pairSearch.search)(search_length);
for (i = 0, i < #pairSearch.pair, i++) {
// uhm... confronto tra due stringhe? '==' non è corretto...
length@StringUtils(pairSearch.pair[i].name)(length2);
pairSearch.pair[i].name.prefix=pairSearch.search;
startsWith@StringUtils(pairSearch.pair[i].name)(prefix);
undef(pairSearch.pair[i].name.prefix);
if (prefix && (search_length == length2)) {
result = pairSearch.pair[i].value;
i = #pairSearch.pair;
found = true
}
};
if (!is_defined(found))
throw (not_found)
}]{nullProcess}
}
......@@ -22,6 +22,7 @@
type HTTPpair: void {
.name :string
.value :string
.format? :string
}
type HTTPRequest:void {
......@@ -43,9 +44,10 @@ type HTTPURLEncoding:string {
interface HTTPInterface {
RequestResponse:
sendRequest (HTTPRequest) (string) throws send_error,
buildURI (HTTPRequest) (string) throws buildURI_fault,
URLencode (HTTPURLEncoding) (string) throws Encoding_fault
parse_www_form (string) (HTTPpair) throws parse_error,
sendRequest (HTTPRequest) (string) throws send_error,
buildURI (HTTPRequest) (string) throws buildURI_fault,
URLencode (HTTPURLEncoding) (string) throws Encoding_fault
}
outputPort HTTP {
......
......@@ -28,6 +28,7 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.apache.commons.io.IOUtils;
......@@ -39,6 +40,7 @@ import jolie.runtime.Value;
import jolie.runtime.ValueVector;
import jolie.runtime.embedding.RequestResponse;
import jolie.runtime.FaultException;
import java.nio.charset.Charset;
public class HTTP extends JavaService
{
......@@ -98,6 +100,28 @@ public static String buildURI (Value req) throws FaultException
}
}
@RequestResponse
public static ValueVector parse (Value data) throws FaultException
{
// URLEncoded values to parsed pairs
URLEncodedUtils decode = new URLEncodedUtils();
try {
List<NameValuePair> values = decode.parse(data.strValue(),
Charset.forName("UTF-8"));
ValueVector result = ValueVector.create();
for (int count = 0; count < values.size(); count++) {
NameValuePair pair = values.get(count);
Value tmp = Value.create();
tmp.getFirstChild("name").setValue(pair.getName());
tmp.getFirstChild("value").setValue(pair.getValue());
result.set(count, tmp);
}
return result;
} catch (Exception e) {
throw new FaultException("parse_error", e);
}
}
private static String sendGet (HttpClient httpclient, Value req)
throws FaultException
{
......@@ -152,7 +176,15 @@ private static String sendPost (HttpClient httpclient, Value req)
UrlEncodedFormEntity entity =
new UrlEncodedFormEntity(postParams);
entity.setContentEncoding("UTF_8");
entity.setContentType("application/json");
if (pair.hasChildren("format")) {
entity.setContentType(
pair.getFirstChild(
"format").strValue());
} else {
// default
entity.setContentType(
"application/json");
}
httppost.setEntity(entity);
}
}
......
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