1 2 #include <petscwebclient.h> 3 4 /* 5 These variables identify the code as a PETSc application to Box. 6 7 See - http://stackoverflow.com/questions/4616553/using-oauth-in-free-open-source-software 8 Users can get their own application IDs - goto https://developers.box.com 9 10 */ 11 #define PETSC_BOX_CLIENT_ID "sse42nygt4zqgrdwi0luv79q1u1f0xza" 12 #define PETSC_BOX_CLIENT_ST "A0Dy4KgOYLB2JIYZqpbze4EzjeIiX5k4" 13 14 #if defined(PETSC_HAVE_SAWS) 15 #include <mongoose.h> 16 17 static volatile char *result = NULL; 18 19 static int PetscBoxWebServer_Private(struct mg_connection *conn) 20 { 21 const struct mg_request_info *request_info = mg_get_request_info(conn); 22 result = (char*) request_info->query_string; 23 return 1; /* Mongoose will now not handle the request */ 24 } 25 26 /* 27 Box can only return an authorization code to a Webserver, hence we need to start one up and wait for 28 the authorization code to arrive from Box 29 */ 30 static PetscErrorCode PetscBoxStartWebServer_Private(void) 31 { 32 PetscErrorCode ierr; 33 int optionsLen = 5; 34 const char *options[optionsLen]; 35 struct mg_callbacks callbacks; 36 struct mg_context *ctx; 37 char keyfile[PETSC_MAX_PATH_LEN]; 38 PetscBool exists; 39 40 PetscFunctionBegin; 41 options[0] = "listening_ports"; 42 options[1] = "8081s"; 43 44 ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr); 45 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 46 if (!exists) { 47 ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 48 ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr); 49 ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr); 50 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 51 if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory"); 52 } 53 54 options[2] = "ssl_certificate"; 55 options[3] = keyfile; 56 options[4] = NULL; 57 58 /* Prepare callbacks structure. We have only one callback, the rest are NULL. */ 59 ierr = PetscMemzero(&callbacks, sizeof(callbacks));CHKERRQ(ierr); 60 callbacks.begin_request = PetscBoxWebServer_Private; 61 ctx = mg_start(&callbacks, NULL, options); 62 if (!ctx) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to start up webserver"); 63 while (!result) {}; 64 PetscFunctionReturn(0); 65 } 66 67 #if defined(PETSC_HAVE_UNISTD_H) 68 #include <unistd.h> 69 #endif 70 71 #undef __FUNCT__ 72 #define __FUNCT__ "PetscBoxAuthorize" 73 /*@C 74 PetscBoxAuthorize - Get authorization and refresh token for accessing Box drive from PETSc 75 76 Not collective, only the first process in MPI_Comm does anything 77 78 Input Parameters: 79 + comm - the MPI communicator 80 - tokensize - size of the token arrays 81 82 Output Parameters: 83 + access_token - can be used with PetscBoxUpload() for this one session 84 - refresh_token - can be used for ever to obtain new access_tokens with PetscBoxRefresh(), guard this like a password 85 it gives access to your Box Drive 86 87 Notes: This call requires stdout and stdin access from process 0 on the MPI communicator 88 89 You can run src/sys/webclient/examples/tutorials/boxobtainrefreshtoken to get a refresh token and then in the future pass it to 90 PETSc programs with -box_refresh_token XXX 91 92 This requires PETSc be installed using --with-saws or --download-saws 93 94 Requires the user have created a self-signed ssl certificate with 95 96 $ saws/CA.pl -newcert (using the passphrase of password) 97 $ cat newkey.pem newcert.pem > sslclient.pem 98 99 and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of 100 silly but it was all I could figure out. 101 102 .seealso: PetscBoxRefresh(), PetscBoxUpload(), PetscURLShorten() 103 104 @*/ 105 PetscErrorCode PetscBoxAuthorize(MPI_Comm comm,char access_token[],char refresh_token[],size_t tokensize) 106 { 107 SSL_CTX *ctx; 108 SSL *ssl; 109 int sock; 110 PetscErrorCode ierr; 111 char buff[8*1024],body[1024],*access,*refresh,*ctmp; 112 PetscMPIInt rank; 113 PetscBool flg; 114 115 PetscFunctionBegin; 116 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 117 if (!rank) { 118 if (!isatty(fileno(PETSC_STDOUT))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Requires users input/output"); 119 ierr = PetscPrintf(comm,"Cut and paste the following into your browser:\n\n" 120 "https://www.box.com/api/oauth2/authorize?" 121 "response_type=code&" 122 "client_id=" 123 PETSC_BOX_CLIENT_ID 124 "&state=PETScState" 125 "\n\n");CHKERRQ(ierr); 126 ierr = PetscBoxStartWebServer_Private();CHKERRQ(ierr); 127 ierr = PetscStrbeginswith((const char*)result,"state=PETScState&code=",&flg);CHKERRQ(ierr); 128 if (!flg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not get expected string from Box got %s",result); 129 ierr = PetscStrncpy(buff,(const char*)result+22,sizeof(buff));CHKERRQ(ierr); 130 131 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 132 ierr = PetscHTTPSConnect("www.box.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 133 ierr = PetscStrcpy(body,"code=");CHKERRQ(ierr); 134 ierr = PetscStrcat(body,buff);CHKERRQ(ierr); 135 ierr = PetscStrcat(body,"&client_id=");CHKERRQ(ierr); 136 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ID);CHKERRQ(ierr); 137 ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr); 138 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ST);CHKERRQ(ierr); 139 ierr = PetscStrcat(body,"&grant_type=authorization_code");CHKERRQ(ierr); 140 141 ierr = PetscHTTPSRequest("POST","www.box.com/api/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 142 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 143 close(sock); 144 145 ierr = PetscStrstr(buff,"\"access_token\" : \"",&access);CHKERRQ(ierr); 146 if (!access) {ierr = PetscStrstr(buff,"\"access_token\":\"",&access);CHKERRQ(ierr);} 147 if (!access) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not receive access token from Box"); 148 access += 18; 149 ierr = PetscStrchr(access,'\"',&ctmp);CHKERRQ(ierr); 150 if (!ctmp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Access token from Box is misformed"); 151 *ctmp = 0; 152 ierr = PetscStrncpy(access_token,access,tokensize);CHKERRQ(ierr); 153 *ctmp = '\"'; 154 155 ierr = PetscStrstr(buff,"\"refresh_token\" : \"",&refresh);CHKERRQ(ierr); 156 if (!refresh) {ierr = PetscStrstr(buff,"\"refresh_token\":\"",&refresh);CHKERRQ(ierr);} 157 if (!refresh) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not receive refresh token from Box"); 158 refresh += 19; 159 ierr = PetscStrchr(refresh,'\"',&ctmp);CHKERRQ(ierr); 160 if (!ctmp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Refresh token from Box is misformed"); 161 *ctmp = 0; 162 ierr = PetscStrncpy(refresh_token,refresh,tokensize);CHKERRQ(ierr); 163 164 ierr = PetscPrintf(comm,"Here is your Box refresh token, save it in a save place, in the future you can run PETSc\n");CHKERRQ(ierr); 165 ierr = PetscPrintf(comm,"programs with the option -box_refresh_token %s\n",refresh);CHKERRQ(ierr); 166 ierr = PetscPrintf(comm,"to access Box Drive automatically\n");CHKERRQ(ierr); 167 } 168 PetscFunctionReturn(0); 169 } 170 #endif 171 172 #undef __FUNCT__ 173 #define __FUNCT__ "PetscBoxRefresh" 174 /*@C 175 PetscBoxRefresh - Get a new authorization token for accessing Box drive from PETSc from a refresh token 176 177 Not collective, only the first process in the MPI_Comm does anything 178 179 Input Parameters: 180 + comm - MPI communicator 181 . refresh token - obtained with PetscBoxAuthorize(), if NULL PETSc will first look for one in the options data 182 if not found it will call PetscBoxAuthorize() 183 - tokensize - size of the output string access_token 184 185 Output Parameter: 186 + access_token - token that can be passed to PetscBoxUpload() 187 - new_refresh_token - the old refresh token is no longer valid, not this is different than Google where the same refresh_token is used forever 188 189 .seealso: PetscURLShorten(), PetscBoxAuthorize(), PetscBoxUpload() 190 191 @*/ 192 PetscErrorCode PetscBoxRefresh(MPI_Comm comm,const char refresh_token[],char access_token[],char new_refresh_token[],size_t tokensize) 193 { 194 SSL_CTX *ctx; 195 SSL *ssl; 196 int sock; 197 PetscErrorCode ierr; 198 char buff[8*1024],body[1024],*access,*ctmp; 199 PetscMPIInt rank; 200 char *refreshtoken = (char*)refresh_token,*refresh; 201 202 PetscFunctionBegin; 203 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 204 if (!rank) { 205 if (!refresh_token) { 206 PetscBool set; 207 ierr = PetscMalloc1(512,&refreshtoken);CHKERRQ(ierr); 208 ierr = PetscOptionsGetString(NULL,"-box_refresh_token",refreshtoken,512,&set);CHKERRQ(ierr); 209 #if defined(PETSC_HAVE_SAWS) 210 if (!set) { 211 ierr = PetscBoxAuthorize(comm,access_token,new_refresh_token,512*sizeof(char));CHKERRQ(ierr); 212 ierr = PetscFree(refreshtoken);CHKERRQ(ierr); 213 PetscFunctionReturn(0); 214 } 215 #else 216 if (!set) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Must provide refresh token with -box_refresh_token XXX"); 217 #endif 218 } 219 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 220 ierr = PetscHTTPSConnect("www.box.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 221 ierr = PetscStrcpy(body,"client_id=");CHKERRQ(ierr); 222 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ID);CHKERRQ(ierr); 223 ierr = PetscStrcat(body,"&client_secret=");CHKERRQ(ierr); 224 ierr = PetscStrcat(body,PETSC_BOX_CLIENT_ST);CHKERRQ(ierr); 225 ierr = PetscStrcat(body,"&refresh_token=");CHKERRQ(ierr); 226 ierr = PetscStrcat(body,refreshtoken);CHKERRQ(ierr); 227 if (!refresh_token) {ierr = PetscFree(refreshtoken);CHKERRQ(ierr);} 228 ierr = PetscStrcat(body,"&grant_type=refresh_token");CHKERRQ(ierr); 229 230 ierr = PetscHTTPSRequest("POST","www.box.com/api/oauth2/token",NULL,"application/x-www-form-urlencoded",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 231 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 232 close(sock); 233 234 ierr = PetscStrstr(buff,"\"access_token\":\"",&access);CHKERRQ(ierr); 235 if (!access) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not receive access token from Box"); 236 access += 16; 237 ierr = PetscStrchr(access,'\"',&ctmp);CHKERRQ(ierr); 238 if (!ctmp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Access token from Box is misformed"); 239 *ctmp = 0; 240 ierr = PetscStrncpy(access_token,access,tokensize);CHKERRQ(ierr); 241 *ctmp = '\"'; 242 243 ierr = PetscStrstr(buff,"\"refresh_token\":\"",&refresh);CHKERRQ(ierr); 244 if (!refresh) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Did not receive refresh token from Box"); 245 refresh += 17; 246 ierr = PetscStrchr(refresh,'\"',&ctmp);CHKERRQ(ierr); 247 if (!ctmp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Refresh token from Box is misformed"); 248 *ctmp = 0; 249 ierr = PetscStrncpy(new_refresh_token,refresh,tokensize);CHKERRQ(ierr); 250 ierr = PetscPrintf(comm,"Here is your new Box refresh token, save it in a save place, in the future you can run PETSc\n");CHKERRQ(ierr); 251 ierr = PetscPrintf(comm,"programs with the option -box_refresh_token %s\n",refresh);CHKERRQ(ierr); 252 ierr = PetscPrintf(comm,"to access Box Drive automatically\n");CHKERRQ(ierr); 253 } 254 PetscFunctionReturn(0); 255 } 256 257 #include <sys/stat.h> 258 259 #undef __FUNCT__ 260 #define __FUNCT__ "PetscBoxUpload" 261 /*@C 262 PetscBoxUpload - Loads a file to the Box Drive 263 264 This routine has not yet been written; it is just copied from Google Drive 265 266 Not collective, only the first process in the MPI_Comm uploads the file 267 268 Input Parameters: 269 + comm - MPI communicator 270 . access_token - obtained with PetscBoxRefresh(), pass NULL to have PETSc generate one 271 - filename - file to upload; if you upload multiple times it will have different names each time on Box Drive 272 273 Options Database: 274 . -box_refresh_token XXX 275 276 Usage Patterns: 277 With PETSc option -box_refresh_token XXX given 278 PetscBoxUpload(comm,NULL,filename); will upload file with no user interaction 279 280 Without PETSc option -box_refresh_token XXX given 281 PetscBoxUpload(comm,NULL,filename); for first use will prompt user to authorize access to Box Drive with their processor 282 283 With PETSc option -box_refresh_token XXX given 284 PetscBoxRefresh(comm,NULL,access_token,sizeof(access_token)); 285 PetscBoxUpload(comm,access_token,filename); 286 287 With refresh token entered in some way by the user 288 PetscBoxRefresh(comm,refresh_token,access_token,sizeof(access_token)); 289 PetscBoxUpload(comm,access_token,filename); 290 291 PetscBoxAuthorize(comm,access_token,refresh_token,sizeof(access_token)); 292 PetscBoxUpload(comm,access_token,filename); 293 294 .seealso: PetscURLShorten(), PetscBoxAuthorize(), PetscBoxRefresh() 295 296 @*/ 297 PetscErrorCode PetscBoxUpload(MPI_Comm comm,const char access_token[],const char filename[]) 298 { 299 SSL_CTX *ctx; 300 SSL *ssl; 301 int sock; 302 PetscErrorCode ierr; 303 char head[1024],buff[8*1024],*body,*title; 304 PetscMPIInt rank; 305 struct stat sb; 306 size_t len,blen,rd; 307 FILE *fd; 308 309 PetscFunctionBegin; 310 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 311 if (!rank) { 312 ierr = PetscStrcpy(head,"Authorization: Bearer ");CHKERRQ(ierr); 313 ierr = PetscStrcat(head,access_token);CHKERRQ(ierr); 314 ierr = PetscStrcat(head,"\r\n");CHKERRQ(ierr); 315 ierr = PetscStrcat(head,"uploadType: multipart\r\n");CHKERRQ(ierr); 316 317 ierr = stat(filename,&sb); 318 if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to stat file: %s",filename); 319 len = 1024 + sb.st_size; 320 ierr = PetscMalloc1(len,&body);CHKERRQ(ierr); 321 ierr = PetscStrcpy(body,"--foo_bar_baz\r\n" 322 "Content-Type: application/json\r\n\r\n" 323 "{" 324 "\"title\": \""); 325 ierr = PetscStrcat(body,filename); 326 ierr = PetscStrcat(body,"\"," 327 "\"mimeType\": \"text.html\"," 328 "\"description\": \" a file\"" 329 "}\r\n\r\n" 330 "--foo_bar_baz\r\n" 331 "Content-Type: text/html\r\n\r\n"); 332 ierr = PetscStrlen(body,&blen);CHKERRQ(ierr); 333 fd = fopen (filename, "r"); 334 if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open file: %s",filename); 335 rd = fread (body+blen, sizeof (unsigned char), sb.st_size, fd); 336 if (rd != (size_t)sb.st_size) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to read entire file: %s %d %d",filename,(int)rd,(int)sb.st_size); 337 fclose(fd); 338 body[blen + rd] = 0; 339 ierr = PetscStrcat(body,"\r\n\r\n" 340 "--foo_bar_baz\r\n"); 341 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr); 342 ierr = PetscHTTPSConnect("www.boxapis.com",443,ctx,&sock,&ssl);CHKERRQ(ierr); 343 ierr = PetscHTTPSRequest("POST","www.boxapis.com/upload/drive/v2/files/",head,"multipart/related; boundary=\"foo_bar_baz\"",body,ssl,buff,sizeof(buff));CHKERRQ(ierr); 344 ierr = PetscFree(body);CHKERRQ(ierr); 345 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr); 346 close(sock); 347 ierr = PetscStrstr(buff,"\"title\"",&title);CHKERRQ(ierr); 348 if (!title) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Upload of file %s failed",filename); 349 } 350 PetscFunctionReturn(0); 351 } 352 353 354