diff options
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/jabber/jabber.c | 7 | ||||
-rw-r--r-- | protocols/jabber/jabber.h | 5 | ||||
-rw-r--r-- | protocols/jabber/sasl.c | 74 |
3 files changed, 69 insertions, 17 deletions
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 9b94b21d..bf849e2a 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -144,6 +144,13 @@ static void jabber_login( account_t *acc ) { jd->fd = jd->r_inpa = jd->w_inpa = -1; + if( strstr( jd->server, ".live.com" ) ) + jd->oauth2_service = &oauth2_service_mslive; + else if( strstr( jd->server, ".facebook.com" ) ) + jd->oauth2_service = &oauth2_service_facebook; + else + jd->oauth2_service = &oauth2_service_google; + /* For the first login with OAuth, we have to authenticate via the browser. For subsequent logins, exchange the refresh token for a valid access token (even though the last one maybe didn't expire yet). */ diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index c68ae343..0a46633e 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -94,6 +94,7 @@ struct jabber_data char *username; /* USERNAME@server */ char *server; /* username@SERVER -=> server/domain, not hostname */ + const struct oauth2_service *oauth2_service; char *oauth2_access_token; /* After changing one of these two (or the priority setting), call @@ -326,6 +327,10 @@ void sasl_oauth2_init( struct im_connection *ic ); int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg ); int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token ); +extern const struct oauth2_service oauth2_service_google; +extern const struct oauth2_service oauth2_service_facebook; +extern const struct oauth2_service oauth2_service_mslive; + /* conference.c */ struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password ); struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name ); diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c index f21a6706..89ab1337 100644 --- a/protocols/jabber/sasl.c +++ b/protocols/jabber/sasl.c @@ -28,13 +28,42 @@ #include "oauth2.h" #include "oauth.h" +const struct oauth2_service oauth2_service_google = +{ + "https://accounts.google.com/o/oauth2/auth", + "https://accounts.google.com/o/oauth2/token", + "urn:ietf:wg:oauth:2.0:oob", + "https://www.googleapis.com/auth/googletalk", + "783993391592.apps.googleusercontent.com", + "6C-Zgf7Tr7gEQTPlBhMUgo7R", +}; +const struct oauth2_service oauth2_service_facebook = +{ + "https://www.facebook.com/dialog/oauth", + "https://graph.facebook.com/oauth/access_token", + "http://www.bitlbee.org/main.php/Facebook/oauth2.html", + "offline_access,xmpp_login", + "126828914005625", + "4b100f0f244d620bf3f15f8b217d4c32", +}; +const struct oauth2_service oauth2_service_mslive = +{ + "https://oauth.live.com/authorize", + "https://oauth.live.com/token", + "http://www.bitlbee.org/main.php/Messenger/oauth2.html", + "wl.messenger", + "000000004C06FCD1", + "IRKlBPzJJAWcY-TbZjiTEJu9tn7XCFaV", +}; + xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) { struct im_connection *ic = data; struct jabber_data *jd = ic->proto_data; struct xt_node *c, *reply; char *s; - int sup_plain = 0, sup_digest = 0, sup_oauth2 = 0, sup_fb = 0; + int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_fb = 0, sup_ms = 0; + int want_oauth = FALSE; if( !sasl_supported( ic ) ) { @@ -61,14 +90,16 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) if( c->text && g_strcasecmp( c->text, "DIGEST-MD5" ) == 0 ) sup_digest = 1; if( c->text && g_strcasecmp( c->text, "X-OAUTH2" ) == 0 ) - sup_oauth2 = 1; + sup_gtalk = 1; if( c->text && g_strcasecmp( c->text, "X-FACEBOOK-PLATFORM" ) == 0 ) sup_fb = 1; + if( c->text && g_strcasecmp( c->text, "X-MESSENGER-OAUTH2" ) == 0 ) + sup_ms = 1; c = c->next; } - if( !sup_plain && !sup_digest ) + if( !sup_plain && !sup_digest && !sup_gtalk && !sup_fb && !sup_ms ) { imcb_error( ic, "No known SASL authentication schemes supported" ); imc_logout( ic, FALSE ); @@ -77,19 +108,12 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) reply = xt_new_node( "auth", NULL, NULL ); xt_add_attr( reply, "xmlns", XMLNS_SASL ); + want_oauth = set_getbool( &ic->acc->set, "oauth" ); - if( set_getbool( &ic->acc->set, "oauth" ) ) + if( sup_gtalk && want_oauth ) { int len; - if( !sup_oauth2 ) - { - imcb_error( ic, "OAuth requested, but not supported by server" ); - imc_logout( ic, FALSE ); - xt_free_node( reply ); - return XT_ABORT; - } - /* X-OAUTH2 is, not *the* standard OAuth2 SASL/XMPP implementation. It's currently used by GTalk and vaguely documented on http://code.google.com/apis/cloudprint/docs/rawxmpp.html . */ @@ -104,11 +128,24 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) reply->text_len = strlen( reply->text ); g_free( s ); } - else if( sup_fb && strstr( ic->acc->pass, "session_key=" ) ) + else if( sup_ms && want_oauth ) + { + xt_add_attr( reply, "mechanism", "X-MESSENGER-OAUTH2" ); + reply->text = g_strdup( jd->oauth2_access_token ); + reply->text_len = strlen( jd->oauth2_access_token ); + } + else if( sup_fb && want_oauth && strstr( ic->acc->pass, "session_key=" ) ) { xt_add_attr( reply, "mechanism", "X-FACEBOOK-PLATFORM" ); jd->flags |= JFLAG_SASL_FB; } + else if( want_oauth ) + { + imcb_error( ic, "OAuth requested, but not supported by server" ); + imc_logout( ic, FALSE ); + xt_free_node( reply ); + return XT_ABORT; + } else if( sup_digest ) { xt_add_attr( reply, "mechanism", "DIGEST-MD5" ); @@ -427,14 +464,14 @@ gboolean sasl_supported( struct im_connection *ic ) void sasl_oauth2_init( struct im_connection *ic ) { + struct jabber_data *jd = ic->proto_data; char *msg, *url; imcb_log( ic, "Starting OAuth authentication" ); /* Temporary contact, just used to receive the OAuth response. */ imcb_add_buddy( ic, "jabber_oauth", NULL ); - url = oauth2_url( &oauth2_service_google, - "https://www.googleapis.com/auth/googletalk" ); + url = oauth2_url( jd->oauth2_service ); msg = g_strdup_printf( "Open this URL in your browser to authenticate: %s", url ); imcb_buddy_msg( ic, "jabber_oauth", msg, 0, 0 ); imcb_buddy_msg( ic, "jabber_oauth", "Respond to this message with the returned " @@ -456,6 +493,7 @@ static void sasl_oauth2_got_token( gpointer data, const char *access_token, cons int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg ) { + struct jabber_data *jd = ic->proto_data; char *code; int ret; @@ -467,7 +505,7 @@ int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg ) code = g_strdup( msg ); g_strstrip( code ); - ret = oauth2_access_token( &oauth2_service_google, OAUTH2_AUTH_CODE, + ret = oauth2_access_token( jd->oauth2_service, OAUTH2_AUTH_CODE, code, sasl_oauth2_got_token, ic ); g_free( code ); @@ -476,7 +514,9 @@ int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg ) int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token ) { - return oauth2_access_token( &oauth2_service_google, OAUTH2_AUTH_REFRESH, + struct jabber_data *jd = ic->proto_data; + + return oauth2_access_token( jd->oauth2_service, OAUTH2_AUTH_REFRESH, refresh_token, sasl_oauth2_got_token, ic ); } |