Are Spring Security RememberMe tokens case-sensitive? - spring-security

Generating my Spring Security 4.0.1 RememberMe token I discovered that this token generating code failed on the token decode:
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
String md5String = DatatypeConverter.printHexBinary(md5Digest.digest((emailAddress + ":" + expiryTime + ":" + password + ":" + key).getBytes()));
String token = emailAddress + ":" + expiryTime + ":" + md5String;
Encoder encoder = Base64.getEncoder();
String encodedToken = encoder.encodeToString(token.getBytes());
But that this code succeeded:
String md5String = DatatypeConverter.printHexBinary(md5Digest.digest((emailAddress + ":" + expiryTime + ":" + password + ":" + key).getBytes())).toLowerCase();
The token decoder expected the MD5 string in lowercase even though the generated MD5 string was upper.
This is the md5String as originally generated (before the toLower()):
testLogin: md5String: E34B931F1F6C02C344AB28A8103F6D23
And this is the error message that shows the lowercase expectation:
Invalid remember-me cookie: Cookie token[2] contained signature 'E34B931F1F6C02C344AB28A8103F6D23' but expected 'e34b931f1f6c02c344ab28a8103f6d23'
(I have an extractRememberMeCookie override that fakes out the cookie from the header)
Is there a better way to do this that doesn't include the toLower() hack?

The problem here was Hex.encode, it uses all lowercase chars.
https://github.com/spring-projects/spring-security/blob/master/crypto/src/main/java/org/springframework/security/crypto/codec/Hex.java

Related

Verification of signature failed Oauth 1 Upwork API

Hi I followed the upwork developers site and the twitter oauth signature generation document and I did the following:
timestamp = int(time.time())
nonce = ''.join([str(random.randint(0, 9)) for i in range(30)])
url = 'https://www.upwork.com/api/auth/v1/info.json'
quoted_url = quote('https://www.upwork.com/api/auth/v1/info.json')
to_hash = 'GET' + '&' + url + '&'
param_string = 'oauth_consumer_key=' + UPWORK_KEY + '&oauth_nonce=' + nonce + '&oauth_signature_method=HMAC-SHA1&oauth_timestamp=' + str(timestamp) + '&oauth_token=' + ACCESS_TOKEN + '&oauth_verifier=' + UPWORK_VERIFIER
to_hash += quote(param_string)
hashed = hmac.new(UPWORK_SECRET + '&' + ACCESS_TOKEN_SECRET, to_hash, hashlib.sha256).hexdigest()
r = requests.get('https://www.upwork.com/api/auth/v1/info.json?oauth_consumer_key=' + UPWORK_KEY + '&oauth_signature=' + hashed + '&oauth_nonce=' + nonce + '&oauth_signature_method=HMAC-SHA1&oauth_timestamp=' + str(timestamp) + '&oauth_token=' + ACCESS_TOKEN + '&oauth_verifier=' + UPWORK_VERIFIER)
r.text
But when I do this, I get:
u'{"server_time":1472207775,"error":{"status":401,"code":401,"message":"Verification of signature failed."}}'
However the following works fine:
client = upwork.Client(UPWORK_KEY, UPWORK_SECRET, oauth_access_token=ACCESS_TOKEN, oauth_access_token_secret=ACCESS_TOKEN_SECRET)
client.auth.get_info()
{u'info': {u'portrait_32_img': u'https://odesk-prod-portraits.s3.amazonaws.com/Users:dasugovinda:PortraitUrl_32?AWSAccessKeyId=1XVAX3FNQZAFC9GJCFR2&Expires=2147483647&Signature=77Ab%2BTxcps9PIYCfPIZZuDpXAiY%3D&1470127549683826', u'capacity': {u'buyer': u'yes', u'affiliate_manager': u'no', u'provider': u'yes'}, u'company_url': u'', u'has_agency': u'0', u'portrait_50_img': u'https://odesk-prod-portraits.s3.amazonaws.com/Users:dasugovinda:PortraitUrl_50?AWSAccessKeyId=1XVAX3FNQZAFC9GJCFR2&Expires=2147483647&Signature=K6Ea0Z6QSmBGcg%2BRCQUAvrai%2FKw%3D&1470127549683826', u'portrait_100_img': u'https://odesk-prod-portraits.s3.amazonaws.com/Users:dasugovinda:PortraitUrl_100?AWSAccessKeyId=1XVAX3FNQZAFC9GJCFR2&Expires=2147483647&Signature=Dht5wFsI%2FDpDDeURkY6KefP4yvc%3D&1470127549683826', u'location': {u'city': u'Santa Clara', u'state': u'CA', u'country': u'United States'}, u'ref': u'5356164', u'profile_url': u'https://www.upwork.com/users/~01d7463c22a4e5c195'}, u'auth_user': {u'timezone': u'America/Tijuana', u'first_name': u'Govinda', u'last_name': u'Dasu', u'timezone_offset': u'-25200'}, u'server_time': u'1472209119'}
Any ideas on what I'm doing wrong?
Thanks to the answer by #Blairg23 here, I figured out the following solution:
url = 'https://www.upwork.com/api/auth/v1/info.json'
auth = OAuth1(UPWORK_KEY, UPWORK_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
r = requests.get(url, auth=auth)
r.text
Just using an already-implemented version of oauth saves you a huge headache.

Google Adwords Reporting HTTP POST request returns 400 response code

I am trying to use Google Adwords Reporting HTTP POST request to retrieve stats for a list of keywords that could exist under multiple Campaigns/Adgroups. This is the API documentation that I was referring to https://developers.google.com/adwords/api/docs/guides/reporting#prepare-the-http-post-request.
Below is scala code that returns 400 error code. What am I doing wrong ? Or is there another way of retrieving data from KEYWORDS_PERFORMANCE_REPORT report type ?
val httpClient = new DefaultHttpClient()
val postRequest=new HttpPost("https://adwords.google.com/api/adwords/reportdownload/v201605")
postRequest.addHeader("Host","adwords.google.com")
postRequest.addHeader("User-Agent", "curl, gzip")
postRequest.addHeader("Accept","*/*")
postRequest.addHeader("Expect","100-continue")
postRequest.addHeader("Accept-Encoding","gzip")
postRequest.addHeader("Content-Type","multipart/form-data; boundary=------------------------12d01fae60c7b559; charset=utf-8")
postRequest.addHeader("Authorization","Bearer 1/*************************************")
postRequest.addHeader("developerToken","/*************************************")")
postRequest.addHeader("clientCustomerId","/*************************************")")
postRequest.addHeader("Parameters","__rdxml: <?xml version=\"1.0\" " +
"encoding=\"UTF-8\"?>" +
"<reportDefinition>" +
" <selector>" +
" <fields>CampaignId</fields>" +
" <fields>AdGroupId</fields>" +
" <fields>Id</fields>" +
" <fields>Criteria</fields>" +
" <fields>CriteriaType</fields>" +
" <fields>Impressions</fields>" +
" <fields>Clicks</fields>" +
" <fields>Cost</fields>" +
" <predicates>" +
" <field>Status</field>" +
" <operator>NOT_IN</operator>" +
" <values>PAUSED</values>" +
" </predicates>" +
" </selector>" +
" <reportName>Criteria performance report #56bd904878715</reportName>" +
" <reportType>CRITERIA_PERFORMANCE_REPORT</reportType>" +
" <dateRangeType>LAST_7_DAYS</dateRangeType>" +
" <downloadFormat>CSV</downloadFormat>" +
"</reportDefinition>")
val httpResponse=httpClient.execute(postRequest)
println(httpResponse.getStatusLine.toString)
Your report definition should go into the POST request's body encoded either as application/x-www-form-urlencoded or multipart/form-data—in your code you are adding it as a header called Parameters.

Twitter API link parser

I am having an issue and tried to do everything regarding this!! even HttpUtility.ParseQueryString won't help!
I am trying to parse twitter links coming from the API in the form of http://t.co/oEVQbihMWu. I need the fully resolved URL.
My code:
richTextBox1.Clear();
richTextBox1.Visible = true;
SearchOptions SO = new SearchOptions();
SO.GeoCode = richTextBox3.Text + "," + richTextBox2.Text + "mi";
TwitterResponse<TwitterSearchResultCollection> TweetSearchResult = TwitterSearch.Search(tokens, "#blogger", SO);
if (TweetSearchResult.Result != RequestResult.Success) richTextBox1.Text = "connection Error";
else
{
string a = null;
foreach (var tweet in TweetSearchResult.ResponseObject)
{
string b = tweet.User.Location.Contains(",") ? tweet.User.Location.Replace(",", "-") : tweet.User.Location;
a += string.Format("{0},{1},{2},{3},{4},{5},{6},{7}", tweet.CreatedDate, b, tweet.User.Id,
tweet.User.ScreenName, tweet.User.Name, tweet.User.NumberOfFollowers, tweet.User.Website, Environment.NewLine);
richTextBox1.AppendText(" " + tweet.CreatedDate + "\n" + tweet.User.Location + "\n" + tweet.User.Id + "\n" + tweet.User.ScreenName + "\n" + tweet.User.Name + "\n" + tweet.User.NumberOfFollowers +
"\n" + tweet.User.Website + "\n" + tweet.Text + "\n\n\n");
}
links being represented by tweet.user.website.
any help? :)
In the API response, there is entities.urls which contains an array of url and expanded_url mappings. Check your library's documentation for equivalent.
Alternatively, if you inspect the response for t.co links, you will find this:
<noscript><META http-equiv="refresh" content="0;URL=http://www.fitnessbydanielle.com"></noscript><title>http://www.fitnessbydanielle.com</title><script>window.opener = null; location.replace("http:\/\/www.fitnessbydanielle.com")</script>
Parse it to get the url.
I managed to crack it.
What I did:
foreach (var tweet in TweetSearchResult.ResponseObject)
{
if(tweet.User.Website != null)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(tweet.User.Website);
req.AllowAutoRedirect = false;
var resp = req.GetResponse();
string realUrl = resp.Headers["Location"];
string b = tweet.User.Location.Contains(",") ? tweet.User.Location.Replace(",", "-") : tweet.User.Location;
a += string.Format("{0},{1},{2},{3},{4},{5},{6},{7}", tweet.CreatedDate, b, tweet.User.Id,
tweet.User.ScreenName, tweet.User.Name, tweet.User.NumberOfFollowers, realUrl, Environment.NewLine);
richTextBox1.AppendText(" " + tweet.CreatedDate + "\n" + tweet.User.Location + "\n" + tweet.User.Id + "\n" + tweet.User.ScreenName + "\n" + tweet.User.Name + "\n" + tweet.User.NumberOfFollowers +
"\n" + realUrl + "\n" + tweet.Text + "\n\n\n");
}
}
File.AppendAllText(#".\BloggerTable.csv", a, Encoding.UTF8);
}
Wrapped it inside a condition so no users without website will show and used a webrequest to get the link. stored the location inside the httprequest header for each and every tweet.

How to sign a string in ruby on rails

I am designing a system in ruby on rails but I want to know how I can sign a text string using a private key. I am supposed to first encode text using ASCII byte array, then compute byte array hash value using SHA1 from a byte array, sign byte array of the hashed array using the private key, and then convert the signed array into base64 . This how am doing it.
require 'openssl'
require 'digest/sha1'
#date = Date.today.strftime("%m/%d/%Y")
text_to_sign = "#{#order.phone_no}" + "#{#order.name}" + "#{#order.pay_type}" + "#{#order.pay_type}" + "1" + "MABIRA" + "81W30DI846" + "#{#date}" + "PULL" + "1" + "#{#cart.total_price}" + "#{#order.phone_no}" + ""
password = 'mypassword'
hashed_text = Digest::SHA1.hexdigest(text_to_sign)
private_key = OpenSSL::PKey::RSA.new(File.read('Mabira.key'), password)
ciphertext = private_key.private_encrypt(hashed_text)
signed_text = [ciphertext].pack('m*')#encoding in base64
puts signed_text
signed_text
Any assistance is welcome.

Twitter oauth Request Token Response code 401

I am working on a twitter oauth login. However, when I do the request_token, the very first step, the response code always return 401 Unauthorized.
I have searched a lot for a week, but I cannot find the solution, please help.
Here is my connection:
URL url = new URL("https://api.twitter.com/oauth/request_token");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestProperty("Host","api.twitter.com");
conn.setRequestProperty("Authorization", data);
conn.setRequestMethod("POST");
conn.connect();
For my data:
String data = "OAuth oauth_nonce=\"" + oauth_nonce
+ "\", oauth_callback=\"" + oauth_callback
+ "\", oauth_signature_method=\"" + oauth_signature_method
+ "\", oauth_timestamp=\"" + oauth_timestamp
+ "\", oauth_consumer_key=\"" + oauth_consumer_key
+ "\", oauth_signature=\"" + oauth_signature
+ "\", oauth_version=\"" + oauth_version + "\"";
Also, I am sure that my signature is right, because I used the parameter of twitter example, I can calculate the same result as its example, so I think my method is right.
Here is my calculation:
String oauth_para = "oauth_callback=" + oauth_callback
+ "&oauth_consumer_key=" + oauth_consumer_key
+ "&oauth_nonce=" + oauth_nonce
+ "&oauth_signature_method=" + oauth_signature_method
+ "&oauth_timestamp=" + oauth_timestamp
+ "&oauth_version=" + oauth_version;
String signingRequests = "POST&" + requestToken + "&" + URLEncoder.encode(oauth_para, "UTF-8");
String key = oauth_consumer_secret + "&";
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
Mac mac = null;
try {
mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
}
catch(Exception e) {
System.err.println("Error: " + e);
}
byte[] rawHmac = mac.doFinal(signingRequests.getBytes());
String oauth_signature = Base64.encodeBytes(rawHmac);
oauth_signature = URLEncoder.encode(oauth_signature);
I understand that the nonce and timestamp should be random and unique. So, my method is like that:
StringBuffer buffer = new StringBuffer("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
StringBuffer sb = new StringBuffer();
Random r = new Random();
int range = buffer.length();
for (int i = 0; i < 43;i ++) {
sb.append(buffer.charAt(r.nextInt(range)));
}
long epoch = System.currentTimeMillis() / 1000;
String oauth_nonce = sb.toString();
Can somebody help me?
P.S: I have also removed my apps, and then create a new one. The result also is the same. Also, the apps is write and read already.
hey,,, I was getting the same problem 1 min ago, but I figured this out. My problem, at least, was that in the configuration of the application(inside twitter), my application type was Client, when should be Browser! So I changed to Browser, put a callback URL and worked fine!!

Resources