2016-01-16 4 views
12

nota: ipums internazionale e ipums USA probabilmente utilizzano lo stesso sistema. ipums usa permette una registrazione più rapida. se vuoi testare il tuo codice, prova https://usa.ipums.org/usa-action/users/request_access per iscriverti!come autenticare un sito web multi-hostname shibboleth con HTTR in R

Sto cercando di scaricare un file di programmazione dal https://international.ipums.org/ con il linguaggio R e HTTR. Ho bisogno di usare httr e non RCurl perché ho bisogno di post-autenticazione scaricare file di grandi dimensioni non nella RAM ma direttamente sul disco. this is currently only possible with httr as far as i know

il codice riproducibile di seguito documenta il mio miglior sforzo per ottenere dalla pagina di accesso (https://international.ipums.org/international-action/users/login) alla pagina di post-autenticazione principale. eventuali suggerimenti o suggerimenti sarebbero apprezzati! Grazie!

my_email <- "[email protected]" 
my_password <- "password" 

tf <- tempfile() 

# use httr, because i need to download a large file after authentication 
# and only httr supports that with its `write_disk()` option 
library(httr) 

# turn off ssl verify, otherwise the subsequent GET command will fail 
set_config(config(ssl_verifypeer = 0L)) 

GET("https://international.ipums.org/Shibboleth.sso/Login?target=https%3A%2F%2Finternational.ipums.org%2Finternational-action%2Fmenu") 

# connect to the starting login page of the website 
(a <- GET("https://international.ipums.org/international-action/users/login" , verbose(info = TRUE))) 

# which takes me through to a lot of websites, but ultimately (in my browser) lands at 
shibboleth_url <- "https://live.identity.popdata.org:443/idp/Authn/UserPassword" 

# construct authentication information? 
base_values <- list("j_username" = my_email , "j_password" = my_password) 
idp_values <- list("j_username" = my_email , "j_password" = my_password , "_idp_authn_lc_key"=subset(a$cookies , domain == "live.identity.popdata.org")$value , "JSESSIONID" = subset(a$cookies , domain == "#HttpOnly_live.identity.popdata.org")$value) 
ipums_values <- list("j_username" = my_email , "j_password" = my_password , "_idp_authn_lc_key"=subset(a$cookies , domain == "live.identity.popdata.org")$value , "JSESSIONID" = subset(a$cookies , domain == "international.ipums.org")$value) 

# i believe this is where the main login should happen, but it looks like it's failing 
GET(shibboleth_url , query = idp_values) 
POST(shibboleth_url , body = base_values) 
writeBin(GET(shibboleth_url , query = idp_values)$content , tf) 

readLines(tf) 
# The MPC account authentication system has encountered an error 
# This error can sometimes occur if you did not close your browser after logging out of an application previously. It may also occur for other reasons. Please close your browser and try your action again."                  

writeBin(GET("https://live.identity.popdata.org/idp/profile/SAML2/Redirect/SSO" , query = idp_values)$content , tf) 
POST("https://live.identity.popdata.org/idp/profile/SAML2/Redirect/SSO" , body = idp_values) 
readLines(tf) 
# same error as above 

# return to the main login page.. 
writeBin(GET("https://international.ipums.org/international-action/menu" , query = ipums_values)$content , tf) 
readLines(tf) 
# ..not logged in 
+0

Avete pensato a RSelenium per questo? – Thomas

+0

@Thomas ciao, non saprei da dove cominciare.sarei aperto ad esso, purché possa scaricare un file arbitrariamente grande _post-authentication_ (che 'httr' può ma' RCurl' non può) –

+1

non tanto da provare senza avere effettivamente un account lì :( – cyberj0g

risposta

2

Devi usare set_cookies() per inviare i cookie al server:

library(httr) 
library(rvest) 
#my_email <- "xxx" 
#my_password <- "yyy" 
tf <- tempfile() 
set_config(config(ssl_verifypeer = 0L)) 

# Get first page 
p1 <- GET("https://international.ipums.org/international-action/users/login" , verbose(info = TRUE)) 

# Post Login credentials 
b2 <- list("j_username" = my_email , "j_password" = my_password) 
c2 <- c(JSESSIONID=p1$cookies[p1$cookies$domain=="#HttpOnly_live.identity.popdata.org",]$value, 
      `_idp_authn_lc_key`=p1$cookies[p1$cookies$domain=="live.identity.popdata.org",]$value) 
p2 <- POST(p1$url,body = b2, set_cookies(.cookies = c2), encode="form") 

# Parse hidden fields 
h2 <- read_html(p2$content) 
form <- h2 %>% html_form() 

# Post hidden fields 
b3 <- list("RelayState"=form[[1]]$fields[[1]]$value, "SAMLResponse"=form[[1]]$fields[[2]]$value) 
c3 <- c(JSESSIONID=p1$cookies[p1$cookies$domain=="#HttpOnly_live.identity.popdata.org",]$value, 
      `_idp_session`=p2$cookies[p2$cookies$name=="_idp_session",]$value, 
      `_idp_authn_lc_key`=p2$cookies[p2$cookies$name=="_idp_authn_lc_key",]$value) 
p3 <- POST(form[[1]]$url , body=b3, set_cookies(.cookies = c3), encode = "form") 

# Get interesting page 
c4 <- c(JSESSIONID=p3$cookies[p1$cookies$domain=="international.ipums.org" && p3$cookies$name=="JSESSIONID",]$value, 
      `_idp_session`=p3$cookies[p3$cookies$name=="_idp_session",]$value, 
      `_idp_authn_lc_key`=p3$cookies[p3$cookies$name=="_idp_authn_lc_key",]$value) 
p4 <- GET("https://international.ipums.org/international-action/menu", set_cookies(.cookies = c4)) 
writeBin(p4$content , tf) 
readLines(tf)[55] 

Poiché il risultato è

[1] " <li class=\"lastItem\"><a href=\"/international-action/users/logout\">Logout</a></li>" 

Penso che si è registrato in ...

+0

perfetto, grazie accreditato qui https://github.com/ajdamico/asdfree/commit/79988d577b98b250a17e606630153b8e67698c2e –

2

@HubertL hanno fatto molti passi nella giusta direzione, tuttavia, penso, la sua risposta non è completa.

Prima di tutto, la cosa principale da guardare quando si sta implementando l'autorizzazione web automatica è i biscotti in uso durante il flusso di lavoro manuale 'normale'. Si può facilmente spiare su di essi con strumenti di sviluppo in qualsiasi browser moderno: enter image description here

Qui, vediamo JSESSIONID e _shibsession* biscotti, prima detiene JSP id di sessione del sito, la seconda è più probabile solo di autorizzazione Shibboleth. Probabilmente il server li ha vincolati in qualche modo, ma lo JSESSIONID non richiede l'autorizzazione e lo si ottiene subito dopo aver aperto il sito. Quindi, dobbiamo ottenere il cookie _shibsession* per il nostro JSESSIONID per essere autorizzato. Questo è ciò che riguarda il processo di autorizzazione di Shibboleth con molti reindirizzamenti. Vedi i commenti nel codice.

login_ipums = function(user, password) 
{ 
    require(httr) 
    require(rvest) 

    set_config(config(ssl_verifypeer = 0L)) 

    #important - httr preserves cookies on subsequent requests to the same host, we don't need that because of sessions expiration 
    handle_reset("https://usa.ipums.org/") 

    #set login and password 
    login1 = GET("https://usa.ipums.org/usa-action/users/login") 
    form_auth = list("j_username" = user , "j_password" = password) 

    l1_cookies=login1$cookies$value 
    names(l1_cookies)=login1$cookies$name 

    #receive auth tokens as html hidden fields in a form 
    login2 = POST(login1$url, body = form_auth, set_cookies(.cookies=l1_cookies), encode="form") 
    login2_form = read_html(login2$content) %>% html_form() 

    l2_cookies=login2$cookies$value 
    names(l2_cookies)=login2$cookies$name 

    #submit the form back (browser submits it back automatically with JS) 
    login3 = POST(login2_form[[1]]$url, body=list(RelayState=login2_form[[1]]$fields$RelayState$value, 
               SAMLResponse=login2_form[[1]]$fields$SAMLResponse$value), 
       set_cookies(.cookies=l2_cookies), 
       encode="form") 

    #now we have what we came for - _shibsession_* and JSESSION id cookie 
    login_cookies = login3$cookies$value 
    names(login_cookies)=login3$cookies$name 

    return=login_cookies 
} 

Dopo la chiamata al login_ipums avremo i seguenti cookie:

> cookies=login_ipums(my_email, my_password) 
> names(cookies) 
[1] "JSESSIONID"  
[2] "_idp_authn_lc_key"    
[3] "_shibsession_7573612e69..." 

Qui, abbiamo sia JSESSIONID e _shibsession_* utilizzati per l'autorizzazione a livello di sito. _idp_authn_lc_key è, probabilmente, non necessario, ma lasciandolo non farà male.

Ora, si può facilmente scaricare i file del genere:

cookies=login_ipums(my_email, my_password) 
target = GET("https://usa.ipums.org/usa-action/downloads/extract_files/usa_00001.dat.gz", 
     set_cookies(.cookies=cookies), 
     write_disk("file.bin", overwrite = TRUE)) 

NOTA IMPORTANTE: Come potete vedere, ho usato IPUMS Stati Uniti d'America, non internazionale. Per verificare il codice con il tuo account, sostituisci usa con international ovunque, incluso lo *-action negli URL.

+0

incredibile, grazie! @ Il codice di HubertL funziona per me, sembra –

+0

Ok, ma nota che il codice di @ HubertL non imposta mai esplicitamente il cookie '_shibsession_ *' (effettivo token di autorizzazione), esso (possibilmente involontariamente) si basa sul meccanismo di persistenza dei cookie 'httr' e che potrebbe essere un questione sulla produzione. – cyberj0g