2015-05-30 16 views
5

Io sono l'attuazione OAuth da Java con la sequenza folowing:Twitter OAuth parametro non valido oauth_verifier

1) Invio https POST: //api.twitter.com/oauth/request_token (con callback) Twitter reponse contiene oauth_token, oauth_token_secret e oauth_callback_confirmed = true

2) Reindirizzamento a https:? //api.twitter.com/oauth/authenticate oauth_token = {oauth_token dalla risposta precedente da Twitter}

appare 3) Twitter form di login, clicco su il pulsante "login".

4) Twitter reindirizza a {} callback_url oauth_token = {questo token è uguale a gettone da OAuth risposta/request_token} & oauth_verifier = {} verificatore

5) https POST:? //api.twitter.com/oauth/access_token con l'intestazione Oauth include oauth_token, corpo del messaggio contiene oauth_verifier = {} verificatore ritornato

6) risposta Twitter = errore durante l'elaborazione della richiesta OAuth: parametro non valido oauth_verifier

Cosa c'è di sbagliato con oauth_verifier?

Compute firma del metodo:

private static String computeSignature(String baseString, String keyString) throws GeneralSecurityException, UnsupportedEncodingException { 
     SecretKey secretKey = null; 

     byte[] keyBytes = keyString.getBytes(); 
     secretKey = new SecretKeySpec(keyBytes, "HmacSHA1"); 

     Mac mac = Mac.getInstance("HmacSHA1"); 
     mac.init(secretKey); 

     byte[] text = baseString.getBytes(); 

     return new String(Base64.encodeBase64(mac.doFinal(text))).trim(); 
    } 

Codice in materia prima richiesta:

String oauth_signature_method = "HMAC-SHA1"; 

    // generate any fairly random alphanumeric string as the "nonce". 
    String uuid_string = UUID.randomUUID().toString(); 
    uuid_string = uuid_string.replaceAll("-", ""); 
    String oauth_nonce = uuid_string; 

    // get the timestamp 
    Calendar tempcal = Calendar.getInstance(); 
    long ts = tempcal.getTimeInMillis(); 
    String oauth_timestamp = (new Long(ts/1000)).toString(); 
    String parameter_string = "oauth_callback=" + OauthConstants.TWITTER_OAUTH_CALLBACK 
      + "&oauth_consumer_key=" + OauthConstants.TWITTER_OAUTH_CONSUMER_KEY 
      + "&oauth_nonce=" + oauth_nonce + "&oauth_signature_method=" 
      + oauth_signature_method + "&oauth_timestamp=" + oauth_timestamp + "&oauth_version=1.0"; 
    String signature_base_string = get_or_post + "&" + encode(twitter_endpoint) + "&" + encode(parameter_string); 
    String oauth_signature = ""; 

    try { 
     oauth_signature = computeSignature(signature_base_string, OauthConstants.TWITTER_OAUTH_CONSUMER_SECRET + "&"); 
    } catch (GeneralSecurityException | UnsupportedEncodingException e) { 
     ...} 

String twitter_endpoint = "https://api.twitter.com/oauth/request_token"; 
String authorization_header_string = "OAuth oauth_callback=\"" + OauthConstants.TWITTER_OAUTH_CALLBACK 
       + "\",oauth_consumer_key=\"" + OauthConstants.TWITTER_OAUTH_CONSUMER_KEY 
       + "\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"" + oauth_timestamp 
       + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_version=\"1.0\",oauth_signature=\"" 
       + encode(oauth_signature) + "\""; 

// Apache httpcore 4.4.1 
HttpProcessor httpproc = HttpProcessorBuilder.create() 
       .add(new RequestContent()) 
       .add(new RequestTargetHost()) 
       .add(new RequestConnControl()) 
       .add(new RequestUserAgent("ApacheHttp/1.1")) 
       .add(new RequestExpectContinue(true)).build(); 

     HttpRequestExecutor httpexecutor = new HttpRequestExecutor(); 
     HttpCoreContext context = HttpCoreContext.create(); 
     HttpHost host = new HttpHost(twitter_endpoint_host, 443); 
     DefaultBHttpClientConnection conn = new DefaultBHttpClientConnection(8 * 1024); 

     context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn); 
     context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, host); 

try { 
       // initialize the HTTPS connection 
       SSLContext sslcontext = SSLContext.getInstance("TLS"); 
       sslcontext.init(null, null, null); 
       SSLSocketFactory ssf = sslcontext.getSocketFactory(); 
       Socket socket = ssf.createSocket(); 
       socket.connect(new InetSocketAddress(host.getHostName(), host.getPort()), 0); 
       conn.bind(socket); 

       BasicHttpEntityEnclosingRequest request2 = new BasicHttpEntityEnclosingRequest("POST", twitter_endpoint_path, HttpVersion.HTTP_1_1); 
       request2.setEntity(new StringEntity("", "UTF-8")); 
       request2.addHeader("Authorization", authorization_header_string); 
       httpexecutor.preProcess(request2, httpproc, context); 
       HttpResponse response2 = httpexecutor.execute(request2, conn, context); 
       httpexecutor.postProcess(response2, httpproc, context); 
} catch(Exception e) {} ... 

Codice in seconda richiesta (Redirect a https OAuth/autenticazione)

public JSONObject getTwitterAuthorizationCodeFromRequestToken(String oauth_token) { 
... 
     String twitter_endpoint = "https://api.twitter.com/oauth/authenticate"; 

     ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); 
     try { 
      FacesContext.getCurrentInstance().getExternalContext().redirect(twitter_endpoint + "?oauth_token=" + encode(oauth_token)); 
     } catch (IOException ex) {...} 
... 
    } 

Codice per il 3 ° richiesta (POST oauth/access_token)

public JSONObject getTwitterAccessTokenFromAuthorizationCode(String verifier_or_pin, String oauth_token) { 
    ... 
String oauth_signature_method = "HMAC-SHA1"; 

    // generate any fairly random alphanumeric string as the "nonce". Nonce = Number used ONCE. 
    String uuid_string = UUID.randomUUID().toString(); 
    uuid_string = uuid_string.replaceAll("-", ""); 
    String oauth_nonce = uuid_string; 

    Calendar tempcal = Calendar.getInstance(); 
    long ts = tempcal.getTimeInMillis(); 
    String oauth_timestamp = (new Long(ts/1000)).toString(); 

    // the parameter string must be in alphabetical order 
    String parameter_string = "oauth_consumer_key=" + OauthConstants.TWITTER_OAUTH_CONSUMER_KEY 
          + "&oauth_nonce=" + oauth_nonce + "&oauth_signature_method=" + oauth_signature_method 
          + "&oauth_timestamp=" + oauth_timestamp + "&oauth_token=" + encode(oauth_token) + "&oauth_version=1.0"; 

    String signature_base_string = get_or_post + "&" + encode(twitter_endpoint) + "&" + encode(parameter_string); 

    String oauth_signature = ""; 
    try { 
     oauth_signature = computeSignature(signature_base_string, OauthConstants.TWITTER_OAUTH_CONSUMER_SECRET + "&"); 
    } catch (GeneralSecurityException | UnsupportedEncodingException e) { 
     ... 
    } 

    String authorization_header_string = "OAuth oauth_consumer_key=\"" + OauthConstants.TWITTER_OAUTH_CONSUMER_KEY 
               + "\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"" + oauth_timestamp 
               + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_version=\"1.0\",oauth_signature=\"" 
               + encode(oauth_signature) + "\",oauth_token=\"" + encode(oauth_token) + "\""; 

    HttpProcessor httpproc = HttpProcessorBuilder.create() 
        .add(new RequestContent()) 
        .add(new RequestTargetHost()) 
        .add(new RequestConnControl()) 
        .add(new RequestUserAgent("ApacheHttp/1.1")) 
        .add(new RequestExpectContinue(true)).build(); 

      HttpRequestExecutor httpexecutor = new HttpRequestExecutor(); 
      HttpCoreContext context = HttpCoreContext.create(); 
      HttpHost host = new HttpHost(twitter_endpoint_host, 443); 
      DefaultBHttpClientConnection conn = new DefaultBHttpClientConnection(8 * 1024); 

      context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn); 
      context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, host); 

    try { 
        SSLContext sslcontext = SSLContext.getInstance("TLS"); 
        sslcontext.init(null, null, null); 
        SSLSocketFactory ssf = sslcontext.getSocketFactory(); 
        Socket socket = ssf.createSocket(); 
        socket.connect(new InetSocketAddress(host.getHostName(), host.getPort()), 0); 
        conn.bind(socket); 

        BasicHttpEntityEnclosingRequest request2 = new BasicHttpEntityEnclosingRequest("POST", twitter_endpoint_path); 
        // Including oauth_verifier value to request body 
        request2.setEntity(new StringEntity("oauth_verifier=" + encode(verifier_or_pin), "UTF-8")); 
        request2.addHeader("Authorization", authorization_header_string); 
        httpexecutor.preProcess(request2, httpproc, context); 
        HttpResponse response2 = httpexecutor.execute(request2, conn, context); 
... 
    } 
+0

Puoi mostrare il tuo codice per farlo? –

+0

@Matthew C domanda aggiornata –

+0

Avendo esattamente lo stesso problema, hai trovato una soluzione? –

risposta

2

Ho sperimentato la stessa identica situazione con il nostro codice di JavaScript. Dopo aver lottato un giorno, ho trovato una soluzione che risolve l'errore. Aggiungendo semplicemente un'intestazione "Content-Type" con valore di "application/x-www-form-urlencoded".

Il mio codice è stato utilizzato per funzionare correttamente, ma smette di funzionare negli ultimi due mesi. La mia ipotesi è che Twitter abbia recentemente modificato l'implementazione della gestione di OAuth che ci obbliga ad aggiungere il tipo di contenuto esplicitamente.

+1

Penso che avrebbero aggiunto alla documentazione, se fosse il caso –

+1

Beh, non possiamo incolpare Twitter perché è definito nelle specifiche HTTP. http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1 – Basuke

+1

Ovviamente, gli ingegneri di Twitter possono essere più gentili perché hanno accettato la richiesta senza tipo di contenuto. Se il messaggio di errore è più ovvio, dì "Errore: è necessaria l'intestazione Content-Type per gestire la richiesta post con i dati.", Potremmo trovare il problema prima. – Basuke