OAuth authentication, invalid signature - oauth
I tired to port the request-oauth library (based on python-request) to Python 3 (with help of 2to3) but I have problems to validate a signature with StatusNet (same API as Twitter).
When I do a request to oauth/request_token, I have no problem but to oauth/access_token I have an error 401 Invalid signature. I don't understand why because it seems to me that what I sign is correct.
For example, with the python 2 code, cf hook.py and auth.py (original from the git repo), I get :
signing_key = '0de1456373dfc9349dd38a48e61fc844&136d6b9a597ee57d4338254812681acd',
signing_raw = 'POST&http%3A%2F%2Fstatus2.dotzero.me%2Fapi%2Foauth%2Faccess_token&oauth_consumer_key%3Dec3ad931b294b51a5ff595c732acb7a5%26oauth_nonce%3D33448267%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1332279747%26oauth_token%3D2131043f3516bcb730d391ed2033a880%26oauth_verifier%3D8816492%26oauth_version%3D1.0'
oauth_hook.token.key = '2131043f3516bcb730d391ed2033a880'
oauth_hook.token.secret = '136d6b9a597ee57d4338254812681acd'
request.data_and_params = {'oauth_version': '1.0', 'oauth_signature': 'xyjxH5QcfZXnG111L7qANZ+ahRI=',
'oauth_token': '2131043f3516bcb730d391ed2033a880', 'oauth_nonce': '33448267',
'oauth_timestamp': '1332279747', 'oauth_verifier': '8816492',
'oauth_consumer_key': 'ec3ad931b294b51a5ff595c732acb7a5',
'oauth_signature_method': 'HMAC-SHA1'}
and with my python 3 port, cf hook.py and auth.py, I get :
signing_key = '0de1456373dfc9349dd38a48e61fc844&136d6b9a597ee57d4338254812681acd',
signing_raw = 'POST&http%3A%2F%2Fstatus2.dotzero.me%2Fapi%2Foauth%2Faccess_token&oauth_consumer_key%3Dec3ad931b294b51a5ff595c732acb7a5%26oauth_nonce%3D52360702%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1332278837%26oauth_token%3D2131043f3516bcb730d391ed2033a880%26oauth_verifier%3D8816492%26oauth_verifier%3D8816492%26oauth_version%3D1.0'
oauth_hook.token.key = '2131043f3516bcb730d391ed2033a880'
oauth_hook.token.secret = '136d6b9a597ee57d4338254812681acd'
request.data_and_params = {'oauth_nonce': '52360702', 'oauth_timestamp': '1332278837',
'oauth_verifier': '8816492', 'oauth_consumer_key': 'ec3ad931b294b51a5ff595c732acb7a5',
'oauth_signature_method': 'HMAC-SHA1', 'oauth_version': '1.0',
'oauth_token': '2131043f3516bcb730d391ed2033a880',
'oauth_signature': 'BRsb11dk++405uaq5pRS+CMUzbo='}
Both looks good to me but the first one succeed and the second returns a 401 error, invalid signature.
In both cases, I get the token.key and token.secret as the result of :
OAuthHook.consumer_key = self.ckey
OAuthHook.consumer_secret = self.csecret
oauth_hook = OAuthHook()
client = requests.session(hooks={'pre_request': oauth_hook})
response = client.post('%soauth/request_token' % (self.url), {'oauth_callback': 'oob'})
# new oauth_hook with the request token
oauth_hook = OAuthHook(response[b'oauth_token'][0],response[b'oauth_token_secret'][0])
Them, I go to oauth/authorize?oauth_token=%s" % oauth_hook.token.key to get authorize the app and get a pincode. After that I can do the problematic request
...
response = client.post('%soauth/request_token' % (self.url), {'oauth_callback': 'oob'})
oauth_hook = OAuthHook(response[b'oauth_token'][0],response[b'oauth_token_secret'][0])
# get the pincode from %soauth/authorize?oauth_token=%s" % (self.url, oauth_hook.token.key)
oauth_hook.token.set_verifier(pincode)
client = requests.session(hooks={'pre_request': oauth_hook})
response = client.post("%soauth/access_token" % (self.url),
{'oauth_verifier': pincode})
The signature code from the auth.py file is
def sign(self, request, consumer, token):
"""Builds the base signature string."""
key, raw = self.signing_base(request, consumer, token)
hashed = hmac.new(key.encode(), raw.encode(), sha1)
# Calculate the digest base 64.
return binascii.b2a_base64(hashed.digest())[:-1]
Any idea why it doesn't work with the py3k code ?
Thank you
Found the answer ! There were two oauth_verifier in the POST request, leading to a wrong signature...
You may need to verify the Authorization header string in your request. Normally it would be of the format:
'Authorization' => 'OAuth
realm="",oauth_timestamp="1243392158",oauth_nonce="VsaPHb",oauth_consumer_key="xxxxxxxxxxxxxxxxxx",oauth_token="xxxxxx-xxxx-xxxxxxxxxxxxxx",oauth_version="1.0",oauth_signature_method="HMAC-SHA1",oauth_signature="xxxxxxxxxxxxxxxxxxxx"'
In the above header value, check that the "oauth_signature" is decoded properly. That is, it should not contain values like: %3D. You can use this tool to decode the string.
This has worked for me. Hope it helps someone.
Related
Why am i still unauthorized? HTTP Twitch 2AuthO request in Lua with coro-http
I am 100% sure that my client-id and client-secret are valid. I used it in my python code and it just worked fine local http = require("coro-http") local json = require("json") local url = "https://id.twitch.tv/oauth2/token" local client_id = "<>" local client_secret = "<>" local headers = { ["Content-Type"] = "application/x-www-form-urlencoded" } local body = "client_id=" .. client_id .. "&client_secret=" .. client_secret .. "&grant_type=client_credentials" local response, w = http.request("POST", url, headers, body) print(w) local data = json.decode(w) local access_token = data.access_token local headers = { ["Client-ID"] = client_id, ["Authorization"] = "Bearer " .. access_token } local response, b = http.request("GET", "https://api.twitch.tv/helix/channels?broadcaster_id=141981764", headers) print(b) Getting token and then do a simple get request
I found this repository which is doing exactly what you're trying to. From the code you provided and the one from the above repo, I would say #LMD comment is the way to go. You need to urlencode your body string. Maybe querystring from luvit could be a good starting point.
hmac authentication in vcl
I am trying to authenticate URL using hamc. I can do the following to verify.My question is how do I parse the URL to extract only part of the URL excluding the hmac parameter. I tried using local variables in vcl but it threw an error. Any suggestions on how to extract the hmac value and URL query parameters as shown below. http://localhost/zzz/?q1=xxx&q2=yyy&hmac=hash if (digest.hmac_md5("key", "q1=xxx&q2=yyy") != "value") { return (synth(401, digest.hmac_md5("key", "http://localhost/zzz/?q1=xxx&q2=yyy"))); } Thanks
You'll want to use the [querystring][1] vmod. As far as I know it does not come pre-packaged, so you will need to build it but it should do exactly what you need. With that you can define regexes/static values to match querystring arguments, and then filter those out or in.
there is no need for a external plugin in that case you can just strip out the hmac=XXX query string parameter, from req.url and store the result in a new variable req.http.url_without_hmac and req.http.hmac to the digest.hmac_md5 see a sample test case: varnishtest "Strip query parameter" server s1 { rxreq txresp rxreq txresp } -start varnish v1 -vcl+backend { import std; sub vcl_recv { # Strip out HMAC parameter # get only the query string, ignore uri set req.http.qs = regsuball(req.url, ".*\?(.*?)$", "?\1"); # strip hmac= from the qs set req.http.url_without_hmac = regsuball(req.http.qs,"\?hmac=[^&]+$",""); # strips when QS = "?hmac=AAA" set req.http.url_without_hmac = regsuball(req.http.url_without_hmac,"\?hmac=[^&]+&","?"); # strips when QS = "?hmac=AAA&foo=bar" set req.http.url_without_hmac = regsuball(req.http.url_without_hmac,"&hmac=[^&]+",""); # strips when QS = "?foo=bar&hmac=AAA" or QS = "?foo=bar&hmac=AAA&bar=baz" # remove the leading ? from the url_without_hmac set req.http.url_without_hmac = regsuball(req.http.url_without_hmac,"^\?(.*)$", "\1"); # extract the hmac= value from the req.http.qs set req.http.hmac = regsuball(req.http.qs, ".*[?&]hmac=([^&]*).*", "\1"); # NOW USE req.http.url_without_hmac for your digest validation and req.http.hmac as the value } sub vcl_deliver { set resp.http.url_without_hmac = req.http.url_without_hmac; set resp.http.hmac = req.http.hmac; } } -start client c1 { txreq -url "/1?a=1&hmac=2&b=1" rxresp expect resp.http.url_without_hmac == "a=1&b=1" expect resp.http.hmac == "2" } -run client c2 { txreq -url "/1?hmac=hello&a=1&b=1" rxresp expect resp.http.url_without_hmac == "a=1&b=1" expect resp.http.hmac == "hello" } -run
Capture full response in Lua Socket call
I am trying to call a REST API through LUA. However, I am not able to capture full raw response returned by the API. Below is the code sample: local http_socket = require("socket.http") local pretty_print = require("pl.pretty") local header = { ["x-device-type"] = "M", ["authorization"] = "ashdjkashd", ["x-app-secret"] = "asdasda", ["x-user-id"] = "asdasdasd" } r, c, h = http_socket.request { method = "GET", -- Validation API Method url = "http://google.com", -- Validation API URL headers = header } print(r .. c) pretty_print.dump(h) I'm using lua 5.3, and luarocks version=2.4.1. In variable c i am getting code, and in h there are a few headers. I need to capture full response returned by the API.
As you may know, luasocket's http.request supports two forms of usage. I'm assuming you need the second form to customize the resty request for that particular API. In this case to capture the response body you'll need to use the sink field with ltn12.sink module. For example local ltn12 = require 'ltn12' -- ... local res = {} r, c, h, s = http_socket.request { method = "GET", -- Validation API Method url = "http://google.com", -- Validation API URL headers = header, sink = ltn12.sink.table(res) } res = table.concat(res) print(res) The table.concat is needed since the response could be comprised of multiple chunk sizes(appended to res as it's received). You can also write it out to file by replacing above with ltn12.sink.file, eg. using ltn12.sink.file(io.stdout) will dump the response to standard output.
erlang google oauth2 protocol for google calling apis
Hello I am writing oauth 2 library to access google api's and my code is as follows jwt_create() -> {ok,PemBin} = file:read_file("your-key-file.pem"), PemEntry = public_key:pem_decode(PemBin), [A,B] = PemEntry, io:format("A:: ~p ~n",[A]), PrivateKey = public_key:pem_entry_decode(PemEntry), JwtHeaderJson = encode_json(jwt_header()), JwtClaimsetJson = encode_json(jwt_claimset()), ComputeSignature = compute_signature(JwtHeaderJson, JwtClaimsetJson, PrivateKey), Z=binary:replace( binary:replace(<<JwtHeaderJson/binary, ".", JwtClaimsetJson/binary, ".", ComputeSignature/binary>>, <<"+">>, <<"-">>, [global]), <<"/">>, <<"_">>, [global]), io:format("JWT:: ~p ~n",[Z]). compute_signature(Header, ClaimSet,#'RSAPrivateKey'{publicExponent=Exponent ,modulus=Modulus ,privateExponent=PrivateExponent}) -> base64:encode(crypto:sign(rsa, sha256, <<Header/binary, ".", ClaimSet/binary>>, [Exponent, Modulus, PrivateExponent])). encode_json(JWToken) -> base64:encode(jsx:encode(JWToken)). I am getting error as follows: exception error: no function clause matching public_key:pem_entry_decode([{'PrivateKeyInfo',<<48,130,4,191,2,1,0,48,13,6,9,42,134, 72,134,247,13,1,1,1,5,0,4,130,4,...>>, not_encrypted}, {'Certificate',<<48,130,3,96,48,130,2,72,160,3,2,1,2,2,8, 79,59,244,35,60,15,3,155,48,...>>, not_encrypted}]) (public_key.erl, line 123) in function googleoauth:jwt_create/0 (src/googleoauth.erl, line 55) Please help me in generating JWS and JWT for OAUTH 2 for accessing google apis
You are passing the wrong thing to public_key:pem_entry_decode/1: This will resolve your problem: PrivateKey = public_key:pem_entry_decode(A), public_key:pem_entry_decode/1 takes a single pem_entry() but a PEM file can contain many entries, perhaps your code PemEntry = public_key:pem_decode(PemBin) should read PemEntries = public_key:pem_decode(PemBin) instead? Also note the line before assumes 2 list entries, you might have meant this instead (not sure your intent here though)? [A|B] = PemEntry,
omniauth-facebook can't convert nil into String
fb = OmniAuth::Strategies::Facebook.new("app_id", "app_secret") client = OAuth2::Client.new("app_id", "app_secret", fb.options.client_options) token = OAuth2::AccessToken.new(client,'access_token', fb.options.access_token_options) fb.instance_variable_set("#access_token", token) fb.auth_hash When I attempt to access the auth_hash, I get: can't convert nil into String Any ideas?
Ok actually, changing the first line to: fb = OmniAuth::Strategies::Facebook.new(nil, "app_id", "app_secret") fixed the issue. I'm not sure what the first parameter represents.