Get husky Oauth2 authentication working

master
teknomunk 1 year ago
parent 2fd65bd84c
commit 4a1edda659

@ -54,5 +54,8 @@ bool route_mastodon_api( struct http_request* req )
return handle_mastodon_api_apps(req);
}
}
// "GET /api/v1/timelines/home?with_muted=true&limit=31"
return false;
}

@ -8,7 +8,7 @@
#include <stdlib.h>
#include <string.h>
bool route_oauth_authorize( struct http_request* req )
static bool handle_oauth_authorize( struct http_request* req )
{
char* client_id = NULL;
char* redirect_uri = NULL;
@ -73,6 +73,11 @@ bool route_oauth_authorize( struct http_request* req )
result =false; goto cleanup;
}
// Store the redirect URI for later use
free(app->redirect_uri);
app->redirect_uri = redirect_uri;
client_app_save( app );
http_request_send_headers( req, 200, "text/html", true );
FILE* f = http_request_get_response_body( req );
#define RENDER
@ -88,11 +93,10 @@ cleanup:
return result;
}
bool route_oauth_do_authorize( struct http_request* req )
static bool handle_oauth_do_authorize( struct http_request* req )
{
char* password = NULL;
char* state = NULL;
char* redirect_uri = NULL;
struct owner* o = owner_new();
struct client_app* app = NULL;
@ -109,8 +113,6 @@ bool route_oauth_do_authorize( struct http_request* req )
password = strdup(form_pull_parser_read_value(fp));
} else if( 0 == strcmp(key,"state") ) {
state = strdup(form_pull_parser_read_value(fp));
} else if( 0 == strcmp(key,"redirect_uri") ) {
redirect_uri = strdup(form_pull_parser_read_value(fp));
} else if( 0 == strcmp(key,"id") ) {
const char* client_id = strdup(form_pull_parser_read_value(fp));
app = client_app_from_id( client_id );
@ -134,7 +136,7 @@ bool route_oauth_do_authorize( struct http_request* req )
char location[512];
char workspace[1024];
const char* fmt = ( state ? "%s?code=%s&state=%s" : "%s?code=%s" );
snprintf( location, 512, fmt, http_escape( redirect_uri, workspace, 1024, ":/" ), app->auth_code, state );
snprintf( location, 512, fmt, http_escape( app->redirect_uri, workspace, 1024, ":/" ), app->auth_code, state );
printf( "redirecting to %s\n", location );
@ -156,13 +158,104 @@ access_denied:
return true;
}
static bool handle_oauth_get_token( struct http_request* req )
{
bool result = true;
char* auth_code = NULL;
struct client_app* app = NULL;
char* redirect_uri = NULL;
char* client_secret = NULL;
FILE* body = http_request_get_request_data(req);
struct form_parser* fp = form_pull_parser_new(body);
if( !fp ) {
goto invalid_request;
}
char* key;
while( key = form_pull_parser_read_key( fp ) ) {
if( 0 == strcmp(key,"grant_type") ) {
if( 0 != strcmp(form_pull_parser_read_value(fp),"authorization_code") ) {
goto invalid_request;
}
} else if( 0 == strcmp(key,"code") ) {
auth_code = strdup(form_pull_parser_read_value(fp));
} else if( 0 == strcmp(key,"client_id") ) {
const char* client_id = strdup(form_pull_parser_read_value(fp));
app = client_app_from_id( client_id );
if( !app ) { goto invalid_request; }
} else if( 0 == strcmp(key,"client_secret") ) {
client_secret = strdup(form_pull_parser_read_value(fp));
} else if( 0 == strcmp(key,"redirect_uri") ) {
redirect_uri = strdup(form_pull_parser_read_value(fp));
} else {
printf( "%s=", key );
printf( "%s\n", form_pull_parser_read_value(fp) );
}
}
form_pull_parser_release(fp);
if( !auth_code ) { goto invalid_request; }
if( !app ) { goto invalid_request; }
if( redirect_uri ) {
if( 0 != strcmp( app->redirect_uri, redirect_uri ) ) {
goto invalid_request;
}
}
if( 0 != strcmp( app->auth_code, auth_code ) ) { goto access_denied; }
if( 0 != strcmp( app->client.secret, client_secret ) ) { goto access_denied; }
// TODO: check code has not expired
client_app_generate_access_token( app );
http_request_begin_send_headers( req, 200, false );
http_request_send_header( req, "Content-Type", "application/json" );
http_request_send_header( req, "Cache-Control", "no-store" );
http_request_end_send_headers( req, false );
FILE* f = http_request_get_response_body( req );
#define RENDER
#include "view/token_grant.json.inc"
#undef RENDER
cleanup:
if( app ) {
client_app_free(app);
}
free(auth_code);
free(client_secret);
free(redirect_uri);
return result;
access_denied:
result = false;
goto cleanup;
invalid_request:
result = false;
goto cleanup;
}
bool route_oauth( struct http_request* req )
{
if( http_request_route( req, "/authorize" ) ) {
if( http_request_route_method(req,"POST") ) {
return route_oauth_do_authorize(req);
return handle_oauth_do_authorize(req);
} else if( http_request_route( req, "?" ) ) {
return route_oauth_authorize(req);
return handle_oauth_authorize(req);
}
} else if( http_request_route( req, "/token" ) ) {
if( http_request_route_method(req,"POST") ) {
return handle_oauth_get_token(req);
}
}

@ -5,6 +5,21 @@
#include <stdlib.h>
#include <string.h>
static char* nullify_empty( char* str )
{
if( !*str ) {
free(str);
return NULL;
}
return str;
}
static char* safe( char* str )
{
if( !str ) { return ""; }
return str;
}
struct client_app* client_app_from_id( const char* client_id )
{
char filename[512];
@ -18,6 +33,9 @@ struct client_app* client_app_from_id( const char* client_id )
app->client.name = NULL;
app->client.id = strdup(client_id);
app->client.secret = NULL;
app->auth_code = NULL;
app->redirect_uri = NULL;
app->access_token = NULL;
struct json_pull_parser* jpp = json_pull_parser_new( f );
if( !jpp ) {
@ -32,10 +50,18 @@ struct client_app* client_app_from_id( const char* client_id )
while( key = json_pull_parser_read_object_key(jpp) ) {
if( 0 == strcmp(key,"secret") ) {
app->client.secret = json_pull_parser_read_string(jpp);
} else if( 0 == strcmp(key,"name") ) {
app->client.name = json_pull_parser_read_string(jpp);
} else if( 0 == strcmp(key,"auth_code") ) {
app->auth_code = json_pull_parser_read_string(jpp);
app->auth_code = nullify_empty( json_pull_parser_read_string(jpp) );
} else if( 0 == strcmp(key,"access_token") ) {
app->access_token = nullify_empty( json_pull_parser_read_string(jpp) );
} else if( 0 == strcmp(key,"redirect_uri") ) {
app->redirect_uri = nullify_empty( json_pull_parser_read_string(jpp) );
}
}
free(key);
@ -66,6 +92,9 @@ struct client_app* client_app_new( const char* client_name )
app->client.id = strdup(id);
app->client.name = strdup(client_name);
app->client.secret = strdup(secret);
app->auth_code = NULL;
app->redirect_uri = NULL;
app->access_token = NULL;
client_app_save(app);
return app;
@ -95,6 +124,9 @@ void client_app_free( struct client_app* app )
free(app->client.name);
free(app->client.secret);
free(app->client.id);
free(app->auth_code);
free(app->redirect_uri);
free(app->access_token);
free(app);
}
@ -109,4 +141,15 @@ void client_app_gen_auth_code( struct client_app* app )
client_app_save(app);
}
void client_app_generate_access_token( struct client_app* app )
{
char* access_token = app->access_token = malloc(65);
for( int i = 0; i < 64; ++i ) {
access_token[i] = 'a'+(rand()%26);
}
access_token[64] = '\0';
client_app_save(app);
}

@ -10,6 +10,7 @@ struct client_app
char* redirect_uri;
char* auth_code;
char* access_token;
// auth_expires
};
@ -18,4 +19,5 @@ struct client_app* client_app_new( const char* client_name );
void client_app_save( struct client_app* app );
void client_app_free( struct client_app* app );
void client_app_gen_auth_code( struct client_app* app );
void client_app_generate_access_token( struct client_app* app );

@ -1,5 +1,7 @@
{
"secret": "%s{app->client.secret}",
"name": "%s{app->client.name}",
"auth_code": "%s{ app->auth_code ? app->auth_code : "" }"
"auth_code": "%s{ safe(app->auth_code) }",
"redirect_uri": "%s{ safe(app->redirect_uri) }",
"access_token": "%s{ safe(app->access_token) }"
}

@ -23,6 +23,5 @@
Password: <input type='password' name='password'/><br/>
<input type="submit" />
<input type='hidden' name='id' value='%s{app->client.id}' />
<input type='hidden' name='redirect_uri' value='%s{redirect_uri}' />
</form>

@ -0,0 +1,4 @@
{
"access_token": "%s{app->access_token}",
"token_type": "Bearer"
}
Loading…
Cancel
Save