2015-10-10 88 views
15

我有一個用例來驗證使用RSA私鑰簽名的OAuth1請求,並在服務器端使用RSA公鑰驗證。使用Twitter joauth和RSA-SHA1驗證OAuth1a簽名請求?

我從Twitter上找到了這個庫,它可以幫助我們驗證/驗證Oauth簽名的請求。 https://github.com/twitter/joauth

我想利用這個庫來驗證Jersey或Spring MVC操作方法的請求。客戶的請求將使用私鑰進行簽名。在我的最後,我會使用客戶端的公鑰來驗證請求。這意味着RSA-SHA1算法。

的Twitter似乎joauth是有用的,但我缺少的是將改變的HttpServletRequest到OAuthRequest

庫自述文件表明,這是工廠,但我無法找到確實javax.servlet.http.HttpServletRequest代碼的代碼 - >com.twitter.joauth.OAuthRequest轉型。

請求驗證發生在具有以下簽名的驗證方法中。

public VerifierResult verify(UnpackedRequest.OAuth1Request request, String tokenSecret, String consumerSecret); 

其次我也想知道這是用最合適的方式/讀取與Twitter joauth RSA公鑰驗證時採用的方法String參數?

+0

您正在使用哪個版本的JOAuth? – Val

回答

1

我從來沒有使用任何庫來通過Twitter驗證用戶。但是我剛剛查看了UnpackedRequest.OAuth1Request。您可以通過填寫所有參數來創建此類的實例。我寫了Twitter OAuth Header創建者,因此您可以直接使用它來填充這些參數或直接發送POST請求,而無需使用庫。

這裏所有您需要的課程:

簽名 - 生成OAuth簽名。

public class Signature { 
    private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1"; 
    public static String calculateRFC2104HMAC(String data, String key) 
      throws java.security.SignatureException 
    { 
     String result; 
     try { 
      SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM); 
      Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM); 
      mac.init(signingKey); 
      byte[] rawHmac = mac.doFinal(data.getBytes()); 
      result = new String(Base64.encodeBase64(rawHmac)); 
     } catch (Exception e) { 
      throw new SignatureException("Failed to generate HMAC : " + e.getMessage()); 
     } 
     return result; 
    } 
} 

NvpComparator - 你在頭需要的參數進行排序。

public class NvpComparator implements Comparator<NameValuePair> { 
    @Override 
    public int compare(NameValuePair arg0, NameValuePair arg1) { 
     String name0 = arg0.getName(); 
     String name1 = arg1.getName(); 
     return name0.compareTo(name1); 
    } 
} 

的OAuth - 對URL編碼。

class OAuth{ 
... 
    public static String percentEncode(String s) { 
      return URLEncoder.encode(s, "UTF-8") 
        .replace("+", "%20").replace("*", "%2A") 
        .replace("%7E", "~"); 
    } 
... 
} 

HeaderCreator - 創建所有需要的參數併產生一個OAuth頭PARAM。

public class HeaderCreator { 
    private String authorization = "OAuth "; 
    private String oAuthSignature; 
    private String oAuthNonce; 
    private String oAuthTimestamp; 
    private String oAuthConsumerSecret; 
    private String oAuthTokenSecret; 

    public String getAuthorization() { 
     return authorization; 
    } 

    public String getoAuthSignature() { 
     return oAuthSignature; 
    } 

    public String getoAuthNonce() { 
     return oAuthNonce; 
    } 

    public String getoAuthTimestamp() { 
     return oAuthTimestamp; 
    } 

    public HeaderCreator(){} 

    public HeaderCreator(String oAuthConsumerSecret){ 
     this.oAuthConsumerSecret = oAuthConsumerSecret; 
    } 

    public HeaderCreator(String oAuthConsumerSecret, String oAuthTokenSecret){ 
     this(oAuthConsumerSecret); 
     this.oAuthTokenSecret = oAuthTokenSecret; 
    } 

    public String getTwitterServerTime() throws IOException, ParseException { 
     HttpsURLConnection con = (HttpsURLConnection) 
       new URL("https://api.twitter.com/oauth/request_token").openConnection(); 
     con.setRequestMethod("HEAD"); 
     con.getResponseCode(); 
     String twitterDate= con.getHeaderField("Date"); 
     DateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH); 
     Date date = formatter.parse(twitterDate); 
     return String.valueOf(date.getTime()/1000L); 
    } 

    public String generatedSignature(String url, String method, List<NameValuePair> allParams, 
            boolean withToken) throws SignatureException { 
     oAuthNonce = String.valueOf(System.currentTimeMillis()); 
     allParams.add(new BasicNameValuePair("oauth_nonce", oAuthNonce)); 
     try { 
      oAuthTimestamp = getTwitterServerTime(); 
      allParams.add(new BasicNameValuePair("oauth_timestamp", oAuthTimestamp)); 
     }catch (Exception ex){ 
      //TODO: Log!! 
     } 

     Collections.sort(allParams, new NvpComparator()); 
     StringBuffer params = new StringBuffer(); 
     for(int i=0;i<allParams.size();i++) 
     { 
      NameValuePair nvp = allParams.get(i); 
      if (i>0) { 
       params.append("&"); 
      } 
      params.append(nvp.getName() + "=" + OAuth.percentEncode(nvp.getValue())); 
     } 
     String signatureBaseStringTemplate = "%s&%s&%s"; 
     String signatureBaseString = String.format(signatureBaseStringTemplate, 
       OAuth.percentEncode(method), 
       OAuth.percentEncode(url), 
       OAuth.percentEncode(params.toString())); 
     String compositeKey = OAuth.percentEncode(oAuthConsumerSecret)+"&"; 
     if(withToken) compositeKey+=OAuth.percentEncode(oAuthTokenSecret); 
     oAuthSignature = Signature.calculateRFC2104HMAC(signatureBaseString, compositeKey); 

     return oAuthSignature; 
    } 

    public String generatedAuthorization(List<NameValuePair> allParams){ 
     authorization = "OAuth "; 
     Collections.sort(allParams, new NvpComparator()); 
     for(NameValuePair nvm : allParams){ 
      authorization+=nvm.getName()+"="+OAuth.percentEncode(nvm.getValue())+", "; 
     } 
     authorization=authorization.substring(0,authorization.length()-2); 
     return authorization; 
    } 

} 

解釋:
1. getTwitterServerTime
在oAuthTimestamp你不需要服務器的時間,但Twitter的服務器的時間。如果您始終在某個Twitter服務器中發送請求,則可以優化它並保存此參數。

2. HeaderCreator.generatedSignature(...)
網址 - 邏輯URL到Twitter API
方法 - GET或POST。您必須始終使用「POST」
allParams - 您知道要生成簽名的參數(「param_name」,「param_value」);
withToken - 如果您知道oAuthTokenSecret爲true。否則爲false。

3. HeaderCreator.generatedAuthorization(...)
在generatedSignature(...)後面使用此方法生成OAuth標題字符串。
allParams - 它是您在generatedSignature(...)中使用的參數加上:現時,簽名,時間戳。始終使用:

allParams.add(new BasicNameValuePair("oauth_nonce", headerCreator.getoAuthNonce())); 
allParams.add(new BasicNameValuePair("oauth_signature", headerCreator.getoAuthSignature())); 
allParams.add(new BasicNameValuePair("oauth_timestamp", headerCreator.getoAuthTimestamp())); 


現在你可以使用它來填充UnpackedRequest.OAuth1Request在您的圖書館。
此處還有一個在沒有庫的情況下在SpringMVC中驗證用戶的示例:
請求 - 發送發佈請求。

public class Requests { 
    public static String sendPost(String url, String urlParameters, Map<String, String> prop) throws Exception { 
     URL obj = new URL(url); 
     HttpsURLConnection con = (HttpsURLConnection) obj.openConnection(); 

     con.setRequestMethod("POST"); 
     if(prop!=null) { 
      for (Map.Entry<String, String> entry : prop.entrySet()) { 
       con.setRequestProperty(entry.getKey(), entry.getValue()); 
      } 
     } 
     con.setDoOutput(true); 
     DataOutputStream wr = new DataOutputStream(con.getOutputStream()); 
     wr.writeBytes(urlParameters); 
     wr.flush(); 
     wr.close(); 
     int responseCode = con.getResponseCode(); 
     BufferedReader in; 
     if(responseCode==200) { 
      in = new BufferedReader(
        new InputStreamReader(con.getInputStream())); 
     }else{ 
      in = new BufferedReader(
        new InputStreamReader(con.getErrorStream())); 
     } 
     String inputLine; 
     StringBuffer response = new StringBuffer(); 
     while ((inputLine = in.readLine()) != null) { 
      response.append(inputLine); 
     } 
     in.close(); 

     return response.toString(); 
    } 
} 

twAuth(...) - 把你的控制器。當用戶想通過Twitter在您的網站進行身份驗證時執行它。

@RequestMapping(value = "/twauth", method = RequestMethod.GET) 
    @ResponseBody 
    public String twAuth(HttpServletResponse response) throws Exception{ 
     try { 
      String url = "https://api.twitter.com/oauth/request_token"; 

      List<NameValuePair> allParams = new ArrayList<NameValuePair>(); 
      allParams.add(new BasicNameValuePair("oauth_callback", "http://127.0.0.1:8080/twlogin")); 
      allParams.add(new BasicNameValuePair("oauth_consumer_key", "2YhNLyum1VY10UrWBMqBnatiT")); 
      allParams.add(new BasicNameValuePair("oauth_signature_method", "HMAC-SHA1")); 
      allParams.add(new BasicNameValuePair("oauth_version", "1.0")); 

      HeaderCreator headerCreator = new HeaderCreator("RUesRE56vVWzN9VFcfA0jCBz9VkvkAmidXj8d1h2tS5EZDipSL"); 
      headerCreator.generatedSignature(url,"POST",allParams,false); 
      allParams.add(new BasicNameValuePair("oauth_nonce", headerCreator.getoAuthNonce())); 
      allParams.add(new BasicNameValuePair("oauth_signature", headerCreator.getoAuthSignature())); 
      allParams.add(new BasicNameValuePair("oauth_timestamp", headerCreator.getoAuthTimestamp())); 

      Map<String, String> props = new HashMap<String, String>(); 
      props.put("Authorization", headerCreator.generatedAuthorization(allParams)); 
      String twitterResponse = Requests.sendPost(url,"",props); 
      Integer indOAuthToken = twitterResponse.indexOf("oauth_token"); 
      String oAuthToken = twitterResponse.substring(indOAuthToken, twitterResponse.indexOf("&",indOAuthToken)); 

      response.sendRedirect("https://api.twitter.com/oauth/authenticate?" + oAuthToken); 
     }catch (Exception ex){ 
      //TODO: Log 
      throw new Exception(); 
     } 
     return "main"; 
    } 

twLogin(...) - 把你的控制器。這是Twitter的回調。

@RequestMapping(value = "/twlogin", method = RequestMethod.GET) 
    public String twLogin(@RequestParam("oauth_token") String oauthToken, 
          @RequestParam("oauth_verifier") String oauthVerifier, 
          Model model, HttpServletRequest request){ 
     try { 
      if(oauthToken==null || oauthToken.equals("") || 
        oauthVerifier==null || oauthVerifier.equals("")) 
       return "main"; 

      String url = "https://api.twitter.com/oauth/access_token"; 

      List<NameValuePair> allParams = new ArrayList<NameValuePair>(); 
      allParams.add(new BasicNameValuePair("oauth_consumer_key", "2YhNLyum1VY10UrWBMqBnatiT")); 
      allParams.add(new BasicNameValuePair("oauth_signature_method", "HMAC-SHA1")); 
      allParams.add(new BasicNameValuePair("oauth_token", oauthToken)); 
      allParams.add(new BasicNameValuePair("oauth_version", "1.0")); 
      NameValuePair oAuthVerifier = new BasicNameValuePair("oauth_verifier", oauthVerifier); 
      allParams.add(oAuthVerifier); 

      HeaderCreator headerCreator = new HeaderCreator("RUesRE56vVWzN9VFcfA0jCBz9VkvkAmidXj8d1h2tS5EZDipSL"); 
      headerCreator.generatedSignature(url,"POST",allParams,false); 
      allParams.add(new BasicNameValuePair("oauth_nonce", headerCreator.getoAuthNonce())); 
      allParams.add(new BasicNameValuePair("oauth_signature", headerCreator.getoAuthSignature())); 
      allParams.add(new BasicNameValuePair("oauth_timestamp", headerCreator.getoAuthTimestamp())); 
      allParams.remove(oAuthVerifier); 

      Map<String, String> props = new HashMap<String, String>(); 
      props.put("Authorization", headerCreator.generatedAuthorization(allParams)); 

      String twitterResponse = Requests.sendPost(url,"oauth_verifier="+oauthVerifier,props); 

      //Get user id 

      Integer startIndexTmp = twitterResponse.indexOf("user_id")+8; 
      Integer endIndexTmp = twitterResponse.indexOf("&",startIndexTmp); 
      if(endIndexTmp<=0) endIndexTmp = twitterResponse.length()-1; 
      Long userId = Long.parseLong(twitterResponse.substring(startIndexTmp, endIndexTmp)); 

      //Do what do you want... 

     }catch (Exception ex){ 
      //TODO: Log 
      throw new Exception(); 
     } 
    } 
+0

感謝分享這樣一個精心製作的答案。 –