Changeset 4a5d885 for protocols/jabber
- Timestamp:
- 2011-07-26T11:58:38Z (13 years ago)
- Branches:
- master
- Children:
- 1174899
- Parents:
- 59c9adb4
- Location:
- protocols/jabber
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/jabber/jabber.c
r59c9adb4 r4a5d885 98 98 struct im_connection *ic = imcb_new( acc ); 99 99 struct jabber_data *jd = g_new0( struct jabber_data, 1 ); 100 struct ns_srv_reply **srvl = NULL, *srv = NULL; 101 char *connect_to, *s; 102 int i; 100 char *s; 103 101 104 102 /* For now this is needed in the _connected() handlers if using … … 139 137 jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free ); 140 138 jd->buddies = g_hash_table_new( g_str_hash, g_str_equal ); 139 140 if( set_getbool( &acc->set, "oauth" ) ) 141 { 142 /* For the first login with OAuth, we have to authenticate via the browser. 143 For subsequent logins, exchange the refresh token for a valid access 144 token (even though the last one maybe didn't expire yet). */ 145 if( strncmp( acc->pass, "refresh_token=", 14 ) != 0 ) 146 sasl_oauth2_init( ic ); 147 else 148 sasl_oauth2_refresh( ic, acc->pass + 14 ); 149 } 150 else 151 jabber_connect( ic ); 152 } 153 154 /* Separate this from jabber_login() so we can do OAuth first if necessary. 155 Putting this in io.c would probably be more correct. */ 156 void jabber_connect( struct im_connection *ic ) 157 { 158 account_t *acc = ic->acc; 159 struct jabber_data *jd = ic->proto_data; 160 int i; 161 char *connect_to; 162 struct ns_srv_reply **srvl = NULL, *srv = NULL; 141 163 142 164 /* Figure out the hostname to connect to. */ … … 280 302 if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) 281 303 return jabber_write( ic, message, strlen( message ) ); 304 305 if( g_strcasecmp( who, "jabber_oauth" ) == 0 ) 306 { 307 if( sasl_oauth2_get_refresh_token( ic, message ) ) 308 { 309 return 1; 310 } 311 else 312 { 313 imcb_error( ic, "OAuth failure" ); 314 imc_logout( ic, TRUE ); 315 } 316 } 282 317 283 318 if( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) ) -
protocols/jabber/jabber.h
r59c9adb4 r4a5d885 92 92 char *username; /* USERNAME@server */ 93 93 char *server; /* username@SERVER -=> server/domain, not hostname */ 94 95 char *oauth2_access_token; 94 96 95 97 /* After changing one of these two (or the priority setting), call … … 232 234 #define XMLNS_IBB "http://jabber.org/protocol/ibb" /* XEP-0047 */ 233 235 236 /* jabber.c */ 237 void jabber_connect( struct im_connection *ic ); 238 234 239 /* iq.c */ 235 240 xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ); … … 316 321 xt_status sasl_pkt_result( struct xt_node *node, gpointer data ); 317 322 gboolean sasl_supported( struct im_connection *ic ); 323 void sasl_oauth2_init( struct im_connection *ic ); 324 int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg ); 325 int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token ); 318 326 319 327 /* conference.c */ -
protocols/jabber/sasl.c
r59c9adb4 r4a5d885 76 76 xt_add_attr( reply, "xmlns", XMLNS_SASL ); 77 77 78 if( sup_oauth2 && set_getbool( &ic->acc->set, "oauth" ) ) 79 { 80 imcb_log( ic, "Open this URL in your browser to authenticate: %s", 81 oauth2_url( &oauth2_service_google, 82 "https://www.googleapis.com/auth/googletalk" ) ); 83 xt_free_node( reply ); 84 reply = NULL; 78 if( set_getbool( &ic->acc->set, "oauth" ) ) 79 { 80 int len; 81 82 if( !sup_oauth2 ) 83 { 84 imcb_error( ic, "OAuth requested, but not supported by server" ); 85 imc_logout( ic, FALSE ); 86 xt_free_node( reply ); 87 return XT_ABORT; 88 } 89 90 /* X-OAUTH2 is, not *the* standard OAuth2 SASL/XMPP implementation. 91 It's currently used by GTalk and vaguely documented on 92 http://code.google.com/apis/cloudprint/docs/rawxmpp.html . */ 93 xt_add_attr( reply, "mechanism", "X-OAUTH2" ); 94 95 len = strlen( jd->username ) + strlen( jd->oauth2_access_token ) + 2; 96 s = g_malloc( len + 1 ); 97 s[0] = 0; 98 strcpy( s + 1, jd->username ); 99 strcpy( s + 2 + strlen( jd->username ), jd->oauth2_access_token ); 100 reply->text = base64_encode( (unsigned char *)s, len ); 101 reply->text_len = strlen( reply->text ); 102 g_free( s ); 85 103 } 86 104 else if( sup_digest ) … … 358 376 return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != 0; 359 377 } 378 379 void sasl_oauth2_init( struct im_connection *ic ) 380 { 381 char *msg, *url; 382 383 imcb_log( ic, "Starting OAuth authentication" ); 384 385 /* Temporary contact, just used to receive the OAuth response. */ 386 imcb_add_buddy( ic, "jabber_oauth", NULL ); 387 url = oauth2_url( &oauth2_service_google, 388 "https://www.googleapis.com/auth/googletalk" ); 389 msg = g_strdup_printf( "Open this URL in your browser to authenticate: %s", url ); 390 imcb_buddy_msg( ic, "jabber_oauth", msg, 0, 0 ); 391 imcb_buddy_msg( ic, "jabber_oauth", "Respond to this message with the returned " 392 "authorization token.", 0, 0 ); 393 394 g_free( msg ); 395 g_free( url ); 396 } 397 398 static gboolean sasl_oauth2_remove_contact( gpointer data, gint fd, b_input_condition cond ) 399 { 400 struct im_connection *ic = data; 401 imcb_remove_buddy( ic, "jabber_oauth", NULL ); 402 return FALSE; 403 } 404 405 static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token ); 406 407 int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg ) 408 { 409 char *code; 410 int ret; 411 412 imcb_log( ic, "Requesting OAuth access token" ); 413 414 /* Don't do it here because the caller may get confused if the contact 415 we're currently sending a message to is deleted. */ 416 b_timeout_add( 1, sasl_oauth2_remove_contact, ic ); 417 418 code = g_strdup( msg ); 419 g_strstrip( code ); 420 ret = oauth2_access_token( &oauth2_service_google, OAUTH2_AUTH_CODE, 421 code, sasl_oauth2_got_token, ic ); 422 423 g_free( code ); 424 return ret; 425 } 426 427 int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token ) 428 { 429 return oauth2_access_token( &oauth2_service_google, OAUTH2_AUTH_REFRESH, 430 refresh_token, sasl_oauth2_got_token, ic ); 431 } 432 433 static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token ) 434 { 435 struct im_connection *ic = data; 436 struct jabber_data *jd; 437 438 if( g_slist_find( jabber_connections, ic ) == NULL ) 439 return; 440 441 jd = ic->proto_data; 442 443 if( access_token == NULL ) 444 { 445 imcb_error( ic, "OAuth failure (missing access token)" ); 446 imc_logout( ic, TRUE ); 447 } 448 if( refresh_token != NULL ) 449 { 450 g_free( ic->acc->pass ); 451 ic->acc->pass = g_strdup_printf( "refresh_token=%s", refresh_token ); 452 } 453 454 g_free( jd->oauth2_access_token ); 455 jd->oauth2_access_token = g_strdup( access_token ); 456 457 jabber_connect( ic ); 458 }
Note: See TracChangeset
for help on using the changeset viewer.