6

Ho sbattuto la testa contro un muro per 3 giorni ora cercando di farlo funzionare.Google OAuth 2.0 Server a server: richiesta errata

POST /oauth2/v3/token HTTP/1.1 
Host: www.googleapis.com 
Content-length: 495 
Content-type: application/x-www-form-urlencoded 
Authorization: Bearer ya29.cgEcY6meBrvaH6oe0nD_PtsFyMVqskiUYi7iJxapKHeEgPoIw8gMt0BJdIvRn1MfcEgzTS3_gTwI1w 
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI5MDgyOTgxNjA1NTktc2R1bGFpbWhsaGpxOTY5M2s1Z2E4c25pZjhh%0D%0ANzhlZ3BAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0%0D%0AdHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvYW5hbHl0aWNzLnJlYWRvbmx5%0D%0AIiwiYXVkIjoiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1dGgyL3Rv%0D%0Aa2VuIiwiZXhwIjoxNDMxNTE0MDUyLCJpYXQiOjE0MzE1MTEwNTJ9.[Cert] 

HTTP/1.1 400 Bad Request 
Content-length: 67 
X-xss-protection: 1; mode=block 
X-content-type-options: nosniff 
Expires: Wed, 13 May 2015 10:08:00 GMT 
Vary: Origin,X-Origin 
Server: GSE 
Cache-control: private, max-age=0 
Date: Wed, 13 May 2015 10:08:00 GMT 
X-frame-options: SAMEORIGIN 
Content-type: application/json; charset=UTF-8 
{ 
    "error_description": "Bad Request", 
    "error": "invalid_grant" 
} 

Quindi, sto creando questo in PL/SQL. Oracle 12c. Sono riuscito a ottenere l'intestazione JWT e JWT Claim impostato per produrre un output uguale alla documentazione di google. Quando creo il certificato, penso che il problema si sia verificato.

  1. 'ho bisogno del "[----- BEGIN CHIAVE PRIVATA -----" e ----- END CHIAVE PRIVATA ----- \ n] come parte del SHA 256 crittografia. Dovrei fare qualcosa con le "Nuove linee"? \ n Dovrei circondarlo di parentesi?

  2. A che punto dovrei essere la codifica URL?

  3. è il codice nel seguente esempio sufficiente per la cifratura ?: http://jastraub.blogspot.co.uk/2009/07/hmacsha256-in-plsql.html

  4. Ho allegato la funzione qui sotto per vedere se è possibile identificare eventuali problemi?

Grazie per il vostro aiuto!

FUNCTION get_JWT (p_token_id ga_app_user.ID_TOKEN%TYPE) 
    RETURN VARCHAR2 
    IS 
    --Plain text 
    baseJWTheader VARCHAR2 (20000); 
    baseclaimSet VARCHAR2 (20000); 
    baseSigKey  VARCHAR2 (20000); 

    --Seconds 

    sysSeconds  NUMBER; 

    --Base64 Encoded 
    JWTheader  VARCHAR2 (20000); 
    claimSet  VARCHAR2 (20000); 
    sigKey   VARCHAR2 (20000); 
    sigContent  VARCHAR2 (20000); 


    --Returned value 
    output   RAW (20000); 
    BEGIN 
    SELECT JWT_HEADER, JWT_CLAIM_SET, SIGNATURE 
     INTO baseJWTheader, baseclaimSet, baseSigKey 
     FROM dwman.ga_app_user au 
    WHERE AU.ID_TOKEN = p_token_id; 

    --DBMS_OUTPUT.PUT_LINE ('Base claim Set ' || baseclaimSet); 
    JWTheader := 
    TRANSLATE (
     UTL_RAW.cast_to_varchar2 (
      UTL_ENCODE.BASE64_ENCODE (UTL_RAW.CAST_TO_RAW (baseJWTheader))), 
     '+/', 
     '-_'); 

    SELECT ( SYSDATE 
      - TO_DATE ('01-01-1970 00:00:00', 'DD-MM-YYYY HH24:MI:SS')) 
     * 24 
     * 60 
     * 60 
    INTO sysSeconds 
    FROM DUAL; 

    baseclaimSet := 
    REPLACE (baseclaimSet, '#EXPIRE#', ROUND (sysSeconds + 3000)); 
    baseclaimSet := REPLACE (baseclaimSet, '#START#', ROUND (sysSeconds)); 

    --DBMS_OUTPUT.PUT_LINE ('Claim Set ' || baseclaimSet); 

    claimSet := UTL_RAW.cast_to_varchar2 (
      UTL_ENCODE.BASE64_ENCODE (UTL_RAW.CAST_TO_RAW (baseclaimSet))); 

    sigKey := baseSigKey; 

    sigContent := JWTheader || '.' || claimSet; 

    --DBMS_OUTPUT.PUT_LINE('Sig Content '||sigContent); 

    sigContent := REPLACE (sigContent, CHR (10), ''); 
    sigContent := REPLACE (sigContent, CHR (13), ''); 
    /* 
    FOR V_TR in 1..length(sigContent) 
    LOOP 
    DBMS_OUTPUT.PUT_LINE (substr(sigContent,V_TR,1)||'='||to_char(ASCII(substr(sigContent,V_TR,1)))); 

    END LOOP; 
    */  
    sigContent := 
     sigContent 
    || '.' 
    || google_signature (sigContent, sigKey); 
    RETURN UTL_URL.ESCAPE(sigContent, TRUE, 'UTF-8'); 
END get_JWT; 
+0

Che cosa stai cercando di fare esattamente qui? invalid_grant normalmente significa che qualcosa non va nel tempo. – DaImTo

+0

Grazie per il commento. Sto cercando di connettermi ai dati googleAnalytics per trasferirli in un datawarehouse. Ho seguito il codice indicato qui: https://developers.google.com/identity/protocols/OAuth2ServiceAccount sotto la sezione HTTP/Rest. Sono vicino a scrivere questo processo ETL in Java, invece, ma non pensavo che sarebbe stato altrettanto faticoso. – Fudztown

+0

e lo fai in PL/SQL? o dovrei dire che stai provando a farlo direttamente in PL/SQL? – DaImTo

risposta

1

codice Lo snippet potrebbe essere solo una parte di quello che hai fatto, ma sembrava mancare gran parte dei passaggi OAuth richiesti da Google per la connessione.

È possibile ottenere maggiori dettagli su ciò che questi passi sono, cercando in questo URL: https://developers.google.com/accounts/docs/OAuth2WebServer#offline

Per il resto di questa risposta, ho descritto le mie esperienze, fare qualcosa di simile (il download di dati da GA, e caricandolo su un database usando SQL Statements).

Inizia ottenendo un consumerKey e consumerSecret per il tuo progetto Google. Dovrai avere un URL a cui Google può reindirizzare, sia quando richiedi la chiave del consumatore, ma anche a fornire a Google durante le tue chiamate OAuth. Devono corrispondere.

Il passaggio successivo è inviare una richiesta GET a Google. Ecco un esempio in C# che puoi creare usando la concatenazione di stringhe SQL.

String URL_AUTH_FIRST = "https://accounts.google.com/o/oauth2/auth"; 
String URL_TOKEN_ENDPOINT_SECOND = "https://accounts.google.com/o/oauth2/token"; 
String url = String.Format(
    "{0}?client_id={1}&redirect_uri={2}&access_type=offline&scope={3}&response_type=code&state={4}&approval_prompt=force", 
     URL_AUTH_FIRST,_consumerKey_web_app,redir_url,scope,state); 

Per eseguire questa operazione è necessario disporre di un browser incorporato. Google.com reindirizzerà quel browser a un sito che è sotto il loro controllo in modo che l'utente debba essere in grado di accedere o rifiutarsi di autorizzare la tua app. Dopo che Google ha le informazioni di cui hanno bisogno, reindirizzano al tuo browser incorporato. È possibile eseguire alcuni passaggi utilizzando copia/incolla nel proprio browser, ma ad un certo punto (descritto di seguito) è necessario eseguire il POST di alcuni dati che non saprei se è possibile farlo da un'applicazione browser.

Google risponderà reindirizzando il browser incorporato a un URL. L'URL contiene dati su di esso. Devi analizzare i parametri sull'URL e cercare il parametro "codice". Se ottieni un URL con "codice" come parametro, devi inviare a Google un formato in un determinato formato.

WebClient client = get_WebClient(); // proprietary to include things like proxy info 
try { 
    NameValueCollection values = new NameValueCollection(); 
    values.Add("client_id", _consumerKey_web_app); 
    values.Add("client_secret", _consumerSecret_web_app_offline); 
    values.Add("grant_type", "authorization_code"); 
    values.Add("redirect_uri", URL_GOOGLE_REDIRECTS_TO_THIS_URL_AFTER_URL_AUTH); 
    values.Add("code", authorization_code); 
    Byte[] responseBytes = client.UploadValues(URL_TOKEN_ENDPOINT_SECOND, values); 
} 

Google restituirà "responseBytes", che sarebbe una stringa JSON formattato, che assomigliano:

{ 
"access_token":"1/fFAGRNJru1FTz70BzhT3Zg", 
        "expires_in":3920, 
        "token_type":"Bearer", 
        "refresh_token":"1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ" 
       } 

L'access_token viene aggiunto alle chiamate API REST.

È possibile fornire una query di GA tramite l'API REST, recuperare i dati e caricarli nel database utilizzando le istruzioni SQL. Questo è ciò che fa la mia app.

È possibile salvare quel refresh_token e fornirlo nelle connessioni future. In effetti, questa intera sequenza deve essere eseguita con un browser o un controllo del browser, in modo interattivo con un utente che si connette. Dopo che è stato completato e hai ricevuto il refresh_token, il tuo SQL può usare e riutilizzare il refresh_token praticamente in-definitivamente , almeno fino a quando la password dell'utente non cambia.

Google restituirà inoltre un errore 401 su base regolare. Ciò significa che devi richiedere nuovamente il token di accesso inviando un nuovo set di valori a Google:

NameValueCollection values = new NameValueCollection(); 
        values.Add("client_id", _consumerKey_web_app); 
        values.Add("client_secret", _consumerSecret_web_app_offline); 
        values.Add("refresh_token", refresh_token); 
        values.Add("grant_type", "refresh_token"); 
        Byte[] responseBytes = client.UploadValues(URL_TOKEN_ENDPOINT_SECOND, values); 
Problemi correlati