#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
/**
- * Authorize namespace
+ * Authorize endpoint
*/
#define GNUNET_REST_API_NS_AUTHORIZE "/idp/authorize"
+/**
+ * Token endpoint
+ */
+#define GNUNET_REST_API_NS_TOKEN "/idp/token"
+
/**
* Login namespace
*/
*/
#define OIDC_COOKIE_HEADER_KEY "Cookie"
+/**
+ * OIDC cookie header information key
+ */
+#define OIDC_AUTHORIZATION_HEADER_KEY "Authorization"
+
+
/**
* OIDC cookie header information key
*/
* OIDC expected scope part while authorizing
*/
#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
+
/**
* OIDC ignored parameter array
*/
/**
* OIDC authorized identities and times hashmap
*/
-struct GNUNET_CONTAINER_MultiHashMap *OIDC_authorized_identities;
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
+
+/**
+ * OIDC authorized identities and times hashmap
+ */
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
/**
* The configuration handle
const struct GNUNET_CONFIGURATION_Handle *cfg;
};
+struct OIDC_Variables
+{
+
+ struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
+
+ char *client_id;
+
+ int is_client_trusted;
+
+ char *redirect_uri;
+
+ char *scope;
+
+ char *state;
+
+ char *nonce;
+
+ char *response_type;
+
+ char *login_identity;
+
+ json_t *post_object;
+};
+
/**
* The ego list
*/
struct EgoEntry *ego_entry;
/**
- * Ptr to current ego private key
+ * Pointer to ego private key
*/
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
+ struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
+
+ /**
+ * OIDC variables
+ */
+ struct OIDC_Variables *oidc;
/**
* The processing state
struct GNUNET_REST_RequestHandle *rest_handle;
/**
- * Zone connection
+ * Handle to NAMESTORE
*/
struct GNUNET_NAMESTORE_Handle *namestore_handle;
+ /**
+ * Iterator for NAMESTORE
+ */
+ struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
+
+ /**
+ * Attribute claim list
+ */
+ struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list;
+
/**
* IDENTITY Operation
*/
*/
char *emsg;
- /**
- * Error response uri
- */
- char *eredirect;
-
/**
* Error response description
*/
};
-
-
/**
* Cleanup lookup handle
* @param handle Handle to clean up
static void
cleanup_handle (struct RequestHandle *handle)
{
+ struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry;
+ struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp;
struct EgoEntry *ego_entry;
struct EgoEntry *ego_tmp;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
GNUNET_free (handle->emsg);
if (NULL != handle->edesc)
GNUNET_free (handle->edesc);
- if (NULL != handle->eredirect)
- GNUNET_free (handle->eredirect);
+ if (NULL != handle->namestore_handle)
+ GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
+ if (NULL != handle->oidc)
+ {
+ if (NULL != handle->oidc->client_id)
+ GNUNET_free(handle->oidc->client_id);
+ if (NULL != handle->oidc->login_identity)
+ GNUNET_free(handle->oidc->login_identity);
+ if (NULL != handle->oidc->nonce)
+ GNUNET_free(handle->oidc->nonce);
+ if (NULL != handle->oidc->redirect_uri)
+ GNUNET_free(handle->oidc->redirect_uri);
+ if (NULL != handle->oidc->response_type)
+ GNUNET_free(handle->oidc->response_type);
+ if (NULL != handle->oidc->scope)
+ GNUNET_free(handle->oidc->scope);
+ if (NULL != handle->oidc->state)
+ GNUNET_free(handle->oidc->state);
+ if (NULL != handle->oidc->post_object)
+ json_decref(handle->oidc->post_object);
+ GNUNET_free(handle->oidc);
+ }
+ if ( NULL != handle->attr_list )
+ {
+ for (claim_entry = handle->attr_list->list_head;
+ NULL != claim_entry;)
+ {
+ claim_tmp = claim_entry;
+ claim_entry = claim_entry->next;
+ GNUNET_free(claim_tmp->claim);
+ GNUNET_free(claim_tmp);
+ }
+ GNUNET_free (handle->attr_list);
+ }
for (ego_entry = handle->ego_head;
NULL != ego_entry;)
{
GNUNET_free (ego_tmp->keystring);
GNUNET_free (ego_tmp);
}
+ if (NULL != handle->attr_it)
+ {
+ GNUNET_free(handle->attr_it);
+ }
GNUNET_free (handle);
}
struct MHD_Response *resp;
char *json_error;
- GNUNET_asprintf (&json_error,
- "{error : %s}",
- handle->emsg);
+ GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
+ handle->emsg,
+ (NULL != handle->edesc) ? handle->edesc : "",
+ (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
+ (NULL != handle->oidc->state) ? handle->oidc->state : "",
+ (NULL != handle->oidc->state) ? "\"" : "");
+ if ( 0 == handle->response_code )
+ {
+ handle->response_code = MHD_HTTP_BAD_REQUEST;
+ }
resp = GNUNET_REST_create_response (json_error);
handle->proc (handle->proc_cls, resp, handle->response_code);
- cleanup_handle (handle);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
GNUNET_free (json_error);
}
struct RequestHandle *handle = cls;
struct MHD_Response *resp;
char* redirect;
- //TODO handle->url is wrong
GNUNET_asprintf (&redirect,
- "%s?error=%s&error_description=%s",
- handle->eredirect, handle->emsg, handle->edesc );
+ "%s?error=%s&error_description=%s%s%s",
+ handle->oidc->redirect_uri, handle->emsg, handle->edesc,
+ (NULL != handle->oidc->state) ? "&state=" : "",
+ (NULL != handle->oidc->state) ? handle->oidc->state : "");
resp = GNUNET_REST_create_response ("");
MHD_add_response_header (resp, "Location", redirect);
handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
- cleanup_handle (handle);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
GNUNET_free (redirect);
}
struct GNUNET_JSONAPI_Resource *json_resource;
struct RequestHandle *handle = cls;
json_t *value;
+ char* tmp_value;
if ((NULL == attr->name) || (NULL == attr->data))
{
attr->name);
GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
- value = json_string (attr->data);
+ tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
+ attr->data,
+ attr->data_size);
+
+ value = json_string (tmp_value);
+
GNUNET_JSONAPI_resource_add_attr (json_resource,
"value",
value);
json_decref (value);
+ GNUNET_free(tmp_value);
GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
}
strlen (rnd_str),
&ticket.rnd,
sizeof (uint64_t));
-// GNUNET_STRINGS_string_to_data (identity_str,
-// strlen (identity_str),
-// &ticket.identity,type filter text
-// sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ GNUNET_STRINGS_string_to_data (identity_str,
+ strlen (identity_str),
+ &ticket.identity,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
GNUNET_STRINGS_string_to_data (audience_str,
strlen (audience_str),
&ticket.audience,
}
/**
- * Function called if we had an error in zone-to-name mapping.
+ * Cookie interpretation
*/
static void
-zone_to_name_error (void *cls)
+cookie_identity_interpretation (struct RequestHandle *handle)
{
- struct RequestHandle *handle = cls;
+ struct GNUNET_HashCode cache_key;
+ char* cookies;
+ struct GNUNET_TIME_Absolute current_time, *relog_time;
+ char delimiter[] = "; ";
- handle->emsg = GNUNET_strdup("unauthorized_client");
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ //gets identity of login try with cookie
+ GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
+ &cache_key);
+ if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
+ &cache_key) )
+ {
+ //splits cookies and find 'Identity' cookie
+ cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
+ handle->oidc->login_identity = strtok(cookies, delimiter);
- GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
- handle->namestore_handle = NULL;
- GNUNET_SCHEDULER_add_now (&do_error, handle);
+ while ( NULL != handle->oidc->login_identity )
+ {
+ if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
+ {
+ break;
+ }
+ handle->oidc->login_identity = strtok (NULL, delimiter);
+ }
+ GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity),
+ &cache_key);
+ if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) )
+ {
+ relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
+ &cache_key);
+ current_time = GNUNET_TIME_absolute_get ();
+ // 30 min after old login -> redirect to login
+ if ( current_time.abs_value_us <= relog_time->abs_value_us )
+ {
+ handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY);
+ handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity);
+ }
+ }
+ else
+ {
+ handle->oidc->login_identity = NULL;
+ }
+ }
}
/**
- * Test if a name mapping was found, if so, continue, else, throw error
- *
- * @param cls closure
- * @param zone_key public key of the zone
- * @param name name that is being mapped (at most 255 characters long)
- * @param rd_count number of entries in @a rd array
- * @param rd array of records with data to store
+ * Login redirection
*/
static void
-zone_to_name_get_cb (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
- const char *name,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
+login_redirection(void *cls)
{
+ char *login_base_url;
+ char *new_redirect;
+ struct MHD_Response *resp;
struct RequestHandle *handle = cls;
-
- if (0 == rd_count)
+ if ( GNUNET_OK
+ == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
+ "address", &login_base_url) )
{
- handle->emsg = GNUNET_strdup("unauthorized_client");
+ GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
+ login_base_url,
+ OIDC_RESPONSE_TYPE_KEY,
+ handle->oidc->response_type,
+ OIDC_CLIENT_ID_KEY,
+ handle->oidc->client_id,
+ OIDC_REDIRECT_URI_KEY,
+ handle->oidc->redirect_uri,
+ OIDC_SCOPE_KEY,
+ handle->oidc->scope,
+ OIDC_STATE_KEY,
+ (NULL != handle->oidc->state) ? handle->oidc->state : "",
+ OIDC_NONCE_KEY,
+ (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
+ resp = GNUNET_REST_create_response ("");
+ MHD_add_response_header (resp, "Location", new_redirect);
+ GNUNET_free(login_base_url);
+ }
+ else
+ {
+ handle->emsg = GNUNET_strdup("server_error");
+ handle->edesc = GNUNET_strdup ("gnunet configuration failed");
handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
-
- GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
- handle->namestore_handle = NULL;
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
+ GNUNET_free(new_redirect);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
}
/**
- * Respond to authorization GET request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
+ * Function called if we had an error in zone-to-name mapping.
*/
static void
-authorize_get_cont (struct GNUNET_REST_RequestHandle *con_handle,
- const char* url,
- void *cls)
+oidc_iteration_error (void *cls)
{
- /** The Authorization Server MUST validate all the OAuth 2.0 parameters
- * according to the OAuth 2.0 specification.
- */
- /**
- * If the sub (subject) Claim is requested with a specific value for the
- * ID Token, the Authorization Server MUST only send a positive response
- * if the End-User identified by that sub value has an active session with
- * the Authorization Server or has been Authenticated as a result of the
- * request. The Authorization Server MUST NOT reply with an ID Token or
- * Access Token for a different user, even if they have an active session
- * with the Authorization Server. Such a request can be made either using
- * an id_token_hint parameter or by requesting a specific Claim Value as
- * described in Section 5.5.1, if the claims parameter is supported by
- * the implementation.
- */
+ struct RequestHandle *handle = cls;
+ handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR");
+ handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+}
- struct MHD_Response *resp;
+static void
+oidc_ticket_issue_cb (void* cls,
+ const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
+{
struct RequestHandle *handle = cls;
- char *response_type;
- char *client_id;
- char *scope;
- char *redirect_uri;
- char *expected_redirect_uri;
- char *state = NULL;
- char *nonce = NULL;
- struct GNUNET_TIME_Absolute current_time, *relog_time;
- char *login_base_url, *new_redirect;
+ struct MHD_Response *resp;
struct GNUNET_HashCode cache_key;
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
- struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
- int number_of_ignored_parameter, iterator;
-
- // REQUIRED value: client_id
- GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
- &cache_key);
- if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
- &cache_key))
- {
- handle->emsg=GNUNET_strdup("invalid_request");
- handle->edesc=GNUNET_strdup("Missing parameter: client_id");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
+ char* ticket_str;
+ char* redirect_uri;
+ char* jwt;
+ handle->idp_op = NULL;
+ resp = GNUNET_REST_create_response ("");
+ if (NULL != ticket) {
+ ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
+ sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket));
+
+
+ //TODO Check if this is right:
+// GNUNET_CRYPTO_hash (ticket_str, strlen (ticket_str), &cache_key);
+// jwt = jwt_create_from_list (handle->oidc->client_pkey,
+// handle->attr_list,
+// handle->priv_key);
+// //TODO Check success of function
+// GNUNET_CONTAINER_multihashmap_put (
+// OIDC_identity_grants, &cache_key, jwt,
+// GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+
+
+ GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s",
+ handle->oidc->redirect_uri,
+ handle->oidc->response_type,
+ ticket_str, handle->oidc->state);
+ MHD_add_response_header (resp, "Location", redirect_uri);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
+ GNUNET_free (redirect_uri);
+ GNUNET_free (ticket_str);
return;
}
- client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
- &cache_key);
- if ( GNUNET_OK
- != GNUNET_CRYPTO_ecdsa_public_key_from_string (client_id,
- strlen (client_id),
- &pubkey) )
- {
- handle->emsg=GNUNET_strdup("unauthorized_client");
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- }
-
- // Checks if client_id is valid:
- handle->namestore_handle = GNUNET_NAMESTORE_connect(cfg);
- zone_pkey = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
- GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, zone_pkey, &pubkey,
- zone_to_name_error, handle, zone_to_name_get_cb,
- handle);
- return;
+ handle->emsg = GNUNET_strdup("server_error");
+ handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
+ GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+}
- // REQUIRED value: redirect_uri
- GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
- &cache_key);
- if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
- &cache_key))
+static void
+oidc_collect_finished_cb (void *cls)
+{
+ struct RequestHandle *handle = cls;
+ handle->attr_it = NULL;
+ handle->ticket_it = NULL;
+ if (NULL == handle->attr_list->list_head)
{
- handle->emsg=GNUNET_strdup("invalid_request");
- handle->edesc=GNUNET_strdup("Missing parameter: redirect_uri");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
+ handle->emsg = GNUNET_strdup("invalid_scope");
+ handle->edesc = GNUNET_strdup("The requested scope is not available.");
+ GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
return;
}
- redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
- &cache_key);
+ handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (handle->idp,
+ &handle->priv_key,
+ &handle->oidc->client_pkey,
+ handle->attr_list,
+ &oidc_ticket_issue_cb,
+ handle);
+}
- GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", client_id);
- // verify the redirect uri matches https://<client_id>.zkey[/xyz]
- if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
+/**
+ * Collect all attributes for an ego
+ */
+static void
+oidc_attr_collect (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+ const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
+{
+ struct RequestHandle *handle = cls;
+ struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
+ char* scope_variables;
+ char* scope_variable;
+ char delimiter[]=" ";
+
+ if ( (NULL == attr->name) || (NULL == attr->data) )
{
- handle->emsg=GNUNET_strdup("invalid_request");
- handle->edesc=GNUNET_strdup("Invalid redirect_uri");
- GNUNET_free(expected_redirect_uri);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
+ GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
return;
}
- handle->eredirect = GNUNET_strdup(redirect_uri);
- // REQUIRED value: response_type
- GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
- &cache_key);
- if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
- &cache_key))
+ scope_variables = GNUNET_strdup(handle->oidc->scope);
+ scope_variable = strtok (scope_variables, delimiter);
+ while (NULL != scope_variable)
{
- handle->emsg=GNUNET_strdup("invalid_request");
- handle->edesc=GNUNET_strdup("Missing parameter: response_type");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
+ if ( 0 == strcmp (attr->name, scope_variable) )
+ {
+ break;
+ }
+ scope_variable = strtok (NULL, delimiter);
}
- response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
- &cache_key);
-
- // REQUIRED value: scope
- GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
- if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
- &cache_key))
+ if ( NULL == scope_variable )
{
- handle->emsg=GNUNET_strdup("invalid_request");
- handle->edesc=GNUNET_strdup("Missing parameter: scope");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+ GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
return;
}
- scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
- &cache_key);
+ GNUNET_free(scope_variables);
- //RECOMMENDED value: state
- GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
- if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
- &cache_key))
- {
- state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
- &cache_key);
- }
+ le = GNUNET_new(struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry);
+ le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr->name, attr->type,
+ attr->data, attr->data_size);
+ GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head,
+ handle->attr_list->list_tail, le);
+ GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
+}
- //OPTIONAL value: nonce
- GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
- if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
- &cache_key))
- {
- nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
- &cache_key);
- }
- number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
- for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
+/**
+ * Cookie and Time check
+ */
+static void
+login_check (void *cls)
+{
+ struct RequestHandle *handle = cls;
+ struct GNUNET_TIME_Absolute current_time, *relog_time;
+ struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
+ struct GNUNET_HashCode cache_key;
+ char *identity_cookie;
+
+ GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity);
+ GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
+ GNUNET_free(identity_cookie);
+ //No login time for identity -> redirect to login
+ if ( GNUNET_YES
+ == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
+ &cache_key) )
{
- GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
- strlen(OIDC_ignored_parameter_array[iterator]),
- &cache_key);
- if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
- &cache_key))
+ relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
+ &cache_key);
+ current_time = GNUNET_TIME_absolute_get ();
+ // 30 min after old login -> redirect to login
+ if ( current_time.abs_value_us <= relog_time->abs_value_us )
{
- handle->emsg=GNUNET_strdup("access_denied");
- GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
- OIDC_ignored_parameter_array[iterator]);
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
- }
- }
-
- // Checks if response_type is 'code'
- if( 0 != strcmp( response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
- {
- handle->emsg=GNUNET_strdup("unsupported_response_type");
- handle->edesc=GNUNET_strdup("The authorization server does not support "
- "obtaining this authorization code.");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
- }
- // Checks if scope contains 'openid'
- if( NULL == strstr( scope, OIDC_EXPECTED_AUTHORIZATION_SCOPE ) )
- {
- handle->emsg=GNUNET_strdup("invalid_scope");
- handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
- "malformed.");
- GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
- return;
+ if ( GNUNET_OK
+ != GNUNET_CRYPTO_ecdsa_public_key_from_string (
+ handle->oidc->login_identity,
+ strlen (handle->oidc->login_identity), &pubkey) )
+ {
+ handle->emsg = GNUNET_strdup("invalid_cookie");
+ handle->edesc = GNUNET_strdup(
+ "The cookie of a login identity is not valid");
+ GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+ return;
+ }
+ // iterate over egos and compare their public key
+ for (handle->ego_entry = handle->ego_head;
+ NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
+ {
+ GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
+ if ( 0
+ == memcmp (&ego_pkey, &pubkey,
+ sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+ {
+ handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
+ handle->ego_entry->ego);
+ handle->resp_object = GNUNET_JSONAPI_document_new ();
+ handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
+ handle->attr_list = GNUNET_new(
+ struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
+ handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (
+ handle->idp, &handle->priv_key, &oidc_iteration_error, handle,
+ &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle);
+ return;
+ }
+ }
+ handle->emsg = GNUNET_strdup("invalid_cookie");
+ handle->edesc = GNUNET_strdup(
+ "The cookie of the login identity is not valid");
+ GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+ return;
+ }
+ //GNUNET_free(relog_time);
}
+}
- //TODO check other values and use them accordingly
+/**
+ * Create a response with requested records
+ *
+ * @param handle the RequestHandle
+ */
+static void
+namestore_iteration_callback (
+ void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+ const char *rname, unsigned int rd_len,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ struct RequestHandle *handle = cls;
+ struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
+ struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
+ int i;
- GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
- &cache_key);
- //No identity-cookie -> redirect to login
- if ( GNUNET_YES
- == GNUNET_CONTAINER_multihashmap_contains (con_handle->header_param_map,
- &cache_key) )
+ for (i = 0; i < rd_len; i++)
{
- //split cookies and find 'Identity' cookie
- char* cookies = GNUNET_CONTAINER_multihashmap_get (
- con_handle->header_param_map, &cache_key);
- char delimiter[] = "; ";
- char *identity_cookie;
- identity_cookie = strtok(cookies, delimiter);
+ if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
+ continue;
- while ( NULL != identity_cookie )
+ if ( NULL != handle->oidc->login_identity )
{
- if ( NULL != strstr (identity_cookie, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
+ GNUNET_CRYPTO_ecdsa_public_key_from_string (
+ handle->oidc->login_identity,
+ strlen (handle->oidc->login_identity),
+ &login_identity_pkey);
+ GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego,
+ ¤t_zone_pkey);
+
+ if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
+ sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
{
- break;
+ if ( 0 == memcmp (&login_identity_pkey, ¤t_zone_pkey,
+ sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+ {
+ handle->oidc->is_client_trusted = GNUNET_YES;
+ }
}
- identity_cookie = strtok (NULL, delimiter);
}
- GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
-
- //No login time for identity -> redirect to login
- if ( GNUNET_YES
- == GNUNET_CONTAINER_multihashmap_contains (OIDC_authorized_identities,
- &cache_key) )
+ else
{
- relog_time = GNUNET_CONTAINER_multihashmap_get (
- OIDC_authorized_identities, &cache_key);
+ if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
+ sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+ {
+ handle->oidc->is_client_trusted = GNUNET_YES;
+ }
+ }
+ }
- current_time = GNUNET_TIME_absolute_get();
+ GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it);
+}
- GNUNET_CONTAINER_multihashmap_remove_all(OIDC_authorized_identities, &cache_key);
- // 30 min after old login -> redirect to login
- if ( current_time.abs_value_us <= relog_time->abs_value_us )
- {
- resp = GNUNET_REST_create_response ("");
+/**
+ * Iteration over all results finished, build final
+ * response.
+ *
+ * @param cls the `struct RequestHandle`
+ */
+static void namestore_iteration_finished_GET (void *cls)
+{
+ struct RequestHandle *handle = cls;
+ struct GNUNET_HashCode cache_key;
- GNUNET_CRYPTO_ecdsa_public_key_from_string (identity_cookie,
- strlen (identity_cookie),
- &pubkey);
+ char *expected_redirect_uri;
+ char *expected_scope;
+ char delimiter[]=" ";
+ int number_of_ignored_parameter, iterator;
- // iterate over egos and compare their public key
-// GNUNET_IDENTITY_PROVIDER_get_attributes_start
- // iterate over scope variables
- char delimiter[] = " ";
- char *scope_attribute;
- scope_attribute = strtok(scope, delimiter);
- while ( NULL != scope_attribute )
- {
- if ( NULL == strstr (scope_attribute, OIDC_EXPECTED_AUTHORIZATION_SCOPE) )
- {
- // claim attribute from ego
- scope_attribute = strtok (NULL, delimiter);
- }
- }
- // create an authorization code
+ handle->ego_entry = handle->ego_entry->next;
-// GNUNET_IDENTITY_PROVIDER_t
+ if(NULL != handle->ego_entry)
+ {
+ handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
+ handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
+ &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
+ &namestore_iteration_finished_GET, handle);
+ return;
+ }
+ if (GNUNET_NO == handle->oidc->is_client_trusted)
+ {
+ handle->emsg = GNUNET_strdup("unauthorized_client");
+ handle->edesc = GNUNET_strdup("The client is not authorized to request an "
+ "authorization code using this method.");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
- MHD_add_response_header (resp, "Location", redirect_uri);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
- cleanup_handle (handle);
- GNUNET_free(relog_time);
- return;
- }
- GNUNET_free(relog_time);
+ // REQUIRED value: redirect_uri
+ GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
+ &cache_key);
+ if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
+ &cache_key))
+ {
+ handle->emsg=GNUNET_strdup("invalid_request");
+ handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ handle->oidc->redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+ &cache_key);
+
+ GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
+ // verify the redirect uri matches https://<client_id>.zkey[/xyz]
+ if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
+ {
+ handle->emsg=GNUNET_strdup("invalid_request");
+ handle->edesc=GNUNET_strdup("Invalid redirect_uri");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ GNUNET_free(expected_redirect_uri);
+ return;
+ }
+ handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
+
+ GNUNET_free(expected_redirect_uri);
+ // REQUIRED value: response_type
+ GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
+ &cache_key);
+ if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
+ &cache_key))
+ {
+ handle->emsg=GNUNET_strdup("invalid_request");
+ handle->edesc=GNUNET_strdup("missing parameter response_type");
+ GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+ return;
+ }
+ handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+ &cache_key);
+ handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
+
+ // REQUIRED value: scope
+ GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
+ if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
+ &cache_key))
+ {
+ handle->emsg=GNUNET_strdup("invalid_request");
+ handle->edesc=GNUNET_strdup("missing parameter scope");
+ GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+ return;
+ }
+ handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+ &cache_key);
+ handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
+
+ //OPTIONAL value: nonce
+ GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
+ &cache_key))
+ {
+ handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+ &cache_key);
+ //TODO: what do we do with the nonce?
+ handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
+ }
+
+ //TODO check other values and use them accordingly
+ number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
+ for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
+ {
+ GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
+ strlen(OIDC_ignored_parameter_array[iterator]),
+ &cache_key);
+ if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
+ &cache_key))
+ {
+ handle->emsg=GNUNET_strdup("access_denied");
+ GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
+ OIDC_ignored_parameter_array[iterator]);
+ GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+ return;
}
}
+ // Checks if response_type is 'code'
+ if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
+ {
+ handle->emsg=GNUNET_strdup("unsupported_response_type");
+ handle->edesc=GNUNET_strdup("The authorization server does not support "
+ "obtaining this authorization code.");
+ GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+ return;
+ }
- // login redirection
- if ( GNUNET_OK
- == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
- "address", &login_base_url) )
+ // Checks if scope contains 'openid'
+ expected_scope = GNUNET_strdup(handle->oidc->scope);
+ expected_scope = strtok (expected_scope, delimiter);
+ while (NULL != expected_scope)
{
- GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
- login_base_url,
- OIDC_RESPONSE_TYPE_KEY,
- response_type,
- OIDC_CLIENT_ID_KEY,
- client_id,
- OIDC_REDIRECT_URI_KEY,
- redirect_uri,
- OIDC_SCOPE_KEY,
- scope,
- OIDC_STATE_KEY,
- (NULL == state) ? state : "",
- OIDC_NONCE_KEY,
- (NULL == nonce) ? nonce : "");
- resp = GNUNET_REST_create_response ("");
- MHD_add_response_header (resp, "Location", new_redirect);
+ if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
+ {
+ break;
+ }
+ expected_scope = strtok (NULL, delimiter);
}
- else
+ if (NULL == expected_scope)
{
- handle->emsg = GNUNET_strdup("No server configuration");
- handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- GNUNET_SCHEDULER_add_now (&do_error, handle);
+ handle->emsg = GNUNET_strdup("invalid_scope");
+ handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
+ "malformed.");
+ GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
return;
}
- handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
- cleanup_handle (handle);
- GNUNET_free(new_redirect);
- return;
+
+ GNUNET_free(expected_scope);
+
+ if( NULL != handle->oidc->login_identity )
+ {
+ GNUNET_SCHEDULER_add_now(&login_check,handle);
+ return;
+ }
+
+ GNUNET_SCHEDULER_add_now(&login_redirection,handle);
}
/**
- * Respond to authorization POST request
+ * Responds to authorization GET request
*
* @param con_handle the connection handle
* @param url the url
* @param cls the RequestHandle
*/
static void
-authorize_post_cont (struct GNUNET_REST_RequestHandle *con_handle,
+authorize_GET_cont (struct GNUNET_REST_RequestHandle *con_handle,
const char* url,
void *cls)
{
- /** The Authorization Server MUST validate all the OAuth 2.0 parameters
- * according to the OAuth 2.0 specification.
- */
- /**
- * If the sub (subject) Claim is requested with a specific value for the
- * ID Token, the Authorization Server MUST only send a positive response
- * if the End-User identified by that sub value has an active session with
- * the Authorization Server or has been Authenticated as a result of the
- * request. The Authorization Server MUST NOT reply with an ID Token or
- * Access Token for a different user, even if they have an active session
- * with the Authorization Server. Such a request can be made either using
- * an id_token_hint parameter or by requesting a specific Claim Value as
- * described in Section 5.5.1, if the claims parameter is supported by
- * the implementation.
- */
-
- struct MHD_Response *resp;
struct RequestHandle *handle = cls;
- const char *response_type;
- const char *client_id;
- char *scope;
- const char *redirect_uri;
- const char *state = NULL;
- const char *nonce = NULL;
- struct GNUNET_TIME_Absolute current_time, *relog_time;
- char *login_base_url;
- char *new_redirect;
- char *expected_redirect_uri;
- json_t *cache_object;
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
- struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
struct GNUNET_HashCode cache_key;
- int number_of_ignored_parameter, iterator;
- json_t *root;
- json_error_t error;
- root = json_loads (handle->rest_handle->data, 0, &error);
+ cookie_identity_interpretation(handle);
+
+ //RECOMMENDED value: state - REQUIRED for answers
+ GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
+ &cache_key))
+ {
+ handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+ &cache_key);
+ handle->oidc->state = GNUNET_strdup (handle->oidc->state);
+ }
// REQUIRED value: client_id
- cache_object = json_object_get (root, OIDC_CLIENT_ID_KEY);
- if( NULL==cache_object || !json_is_string(cache_object))
+ GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
+ &cache_key);
+ if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
+ &cache_key))
{
handle->emsg=GNUNET_strdup("invalid_request");
- handle->edesc=GNUNET_strdup("Missing parameter: client_id");
+ handle->edesc=GNUNET_strdup("missing parameter client_id");
+ handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- client_id = json_string_value(cache_object);
+ handle->oidc->client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+ &cache_key);
+ handle->oidc->client_id = GNUNET_strdup (handle->oidc->client_id);
+
if ( GNUNET_OK
- != GNUNET_CRYPTO_ecdsa_public_key_from_string (client_id,
- strlen (client_id),
- &pubkey) )
+ != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
+ strlen (handle->oidc->client_id),
+ &handle->oidc->client_pkey) )
+ {
+ handle->emsg = GNUNET_strdup("unauthorized_client");
+ handle->edesc = GNUNET_strdup("The client is not authorized to request an "
+ "authorization code using this method.");
+ handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+
+ if ( NULL == handle->ego_head )
{
- handle->emsg=GNUNET_strdup("unauthorized_client");
+ //TODO throw error or ignore if egos are missing?
+ handle->emsg = GNUNET_strdup("server_error");
+ handle->edesc = GNUNET_strdup ("Egos are missing");
handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
}
+ handle->ego_entry = handle->ego_head;
+ handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
+ handle->oidc->is_client_trusted = GNUNET_NO;
+
// Checks if client_id is valid:
- handle->namestore_handle = GNUNET_NAMESTORE_connect(cfg);
- zone_pkey = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
- //TODO: fix
-// GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, zone_pkey, &pubkey,
-// zone_to_name_error, handle, zone_to_name_cb,
-// handle);
+ handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
+ handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
+ handle, &namestore_iteration_callback, handle,
+ &namestore_iteration_finished_GET, handle);
+}
+
+/**
+ * Iteration over all results finished, build final
+ * response.
+ *
+ * @param cls the `struct RequestHandle`
+ */
+static void namestore_iteration_finished_POST (void *cls)
+{
+ struct RequestHandle *handle = cls;
+ json_t *cache_object;
+ char *expected_redirect_uri;
+ char *expected_scope;
+ char delimiter[]=" ";
+ int number_of_ignored_parameter, iterator;
+
+
+ handle->ego_entry = handle->ego_entry->next;
+
+ if(NULL != handle->ego_entry){
+ handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
+ handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
+ &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
+ &namestore_iteration_finished_POST, handle);
+ return;
+ }
+ if (GNUNET_YES != handle->oidc->is_client_trusted)
+ {
+ handle->emsg = GNUNET_strdup("unauthorized_client");
+ handle->edesc = GNUNET_strdup("The client is not authorized to request an "
+ "authorization code using this method.");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
// REQUIRED value: redirect_uri
- cache_object = json_object_get (root, OIDC_REDIRECT_URI_KEY);
- if( NULL==cache_object || !json_is_string(cache_object))
+ cache_object = json_object_get (handle->oidc->post_object, OIDC_REDIRECT_URI_KEY);
+ if ( NULL == cache_object || !json_is_string(cache_object) )
{
handle->emsg=GNUNET_strdup("invalid_request");
- handle->edesc=GNUNET_strdup("Missing parameter: redirect_uri");
+ handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- redirect_uri = json_string_value(cache_object);
-
- GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", client_id);
+ handle->oidc->redirect_uri = json_string_value (cache_object);
+ GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
// verify the redirect uri matches https://<client_id>.zkey[/xyz]
- if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
+ if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
{
handle->emsg=GNUNET_strdup("invalid_request");
handle->edesc=GNUNET_strdup("Invalid redirect_uri");
- GNUNET_free(expected_redirect_uri);
GNUNET_SCHEDULER_add_now (&do_error, handle);
+ GNUNET_free(expected_redirect_uri);
return;
}
- handle->eredirect = GNUNET_strdup(redirect_uri);
+ handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
+ GNUNET_free(expected_redirect_uri);
// REQUIRED value: response_type
- cache_object = json_object_get (root, OIDC_RESPONSE_TYPE_KEY);
- if( NULL==cache_object || !json_is_string(cache_object))
+ cache_object = json_object_get (handle->oidc->post_object, OIDC_RESPONSE_TYPE_KEY);
+ if ( NULL == cache_object || !json_is_string(cache_object) )
{
handle->emsg=GNUNET_strdup("invalid_request");
- handle->edesc=GNUNET_strdup("Missing parameter: response_type");
+ handle->edesc=GNUNET_strdup("missing parameter response_type");
GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
return;
}
- response_type = json_string_value(cache_object);
+ handle->oidc->response_type = json_string_value (cache_object);
+ handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
// REQUIRED value: scope
- cache_object = json_object_get (root, OIDC_SCOPE_KEY);
- if( NULL==cache_object || !json_is_string(cache_object))
+ cache_object = json_object_get (handle->oidc->post_object, OIDC_SCOPE_KEY);
+ if ( NULL == cache_object || !json_is_string(cache_object) )
{
handle->emsg=GNUNET_strdup("invalid_request");
- handle->edesc=GNUNET_strdup("Missing parameter: scope");
+ handle->edesc=GNUNET_strdup("missing parameter scope");
GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
return;
}
- scope = json_string_value(cache_object);
-
- //RECOMMENDED value: state
- cache_object = json_object_get (root, OIDC_STATE_KEY);
- if( NULL!=cache_object || json_is_string(cache_object))
- {
- state = json_string_value(cache_object);
- }
+ handle->oidc->scope = json_string_value (cache_object);
+ handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
//OPTIONAL value: nonce
- cache_object = json_object_get (root, OIDC_NONCE_KEY);
- if( NULL!=cache_object || json_is_string(cache_object))
+ cache_object = json_object_get (handle->oidc->post_object, OIDC_NONCE_KEY);
+ if ( NULL != cache_object && json_is_string(cache_object) )
{
- nonce = json_string_value(cache_object);
+ handle->oidc->nonce = json_string_value (cache_object);
+ //TODO: what do we do with the nonce?
+ handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
}
//TODO check other values and use them accordingly
number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
{
- cache_object = json_object_get (root, OIDC_ignored_parameter_array[iterator]);
- if(json_is_string(cache_object))
+ cache_object = json_object_get (handle->oidc->post_object, OIDC_ignored_parameter_array[iterator]);
+ if( NULL != cache_object && json_is_string(cache_object) )
{
handle->emsg=GNUNET_strdup("access_denied");
GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
}
// Checks if response_type is 'code'
- if( 0 != strcmp( response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
+ if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
{
handle->emsg=GNUNET_strdup("unsupported_response_type");
handle->edesc=GNUNET_strdup("The authorization server does not support "
GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
return;
}
+
// Checks if scope contains 'openid'
- if( NULL == strstr( scope, OIDC_EXPECTED_AUTHORIZATION_SCOPE ) )
+ expected_scope = GNUNET_strdup(handle->oidc->scope);
+ expected_scope = strtok (expected_scope, delimiter);
+ while (NULL != expected_scope)
+ {
+ if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
+ {
+ break;
+ }
+ expected_scope = strtok (NULL, delimiter);
+ }
+ if (NULL == expected_scope)
{
- handle->emsg=GNUNET_strdup("invalid_scope");
+ handle->emsg = GNUNET_strdup("invalid_scope");
handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
"malformed.");
GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
return;
}
+ GNUNET_free(expected_scope);
- GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
- &cache_key);
- //No identity-cookie -> redirect to login
- if ( GNUNET_YES
- == GNUNET_CONTAINER_multihashmap_contains (con_handle->header_param_map,
- &cache_key) )
+ if( NULL != handle->oidc->login_identity )
{
- //split cookies and find 'Identity' cookie
- char* cookies = GNUNET_CONTAINER_multihashmap_get (
- con_handle->header_param_map, &cache_key);
- char delimiter[] = "; ";
- char *identity_cookie;
- identity_cookie = strtok(cookies, delimiter);
-
- while ( NULL != identity_cookie )
- {
- if ( NULL != strstr (identity_cookie, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
- {
- break;
- }
- identity_cookie = strtok (NULL, delimiter);
- }
- GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
-
- //No login time for identity -> redirect to login
- if ( GNUNET_YES
- == GNUNET_CONTAINER_multihashmap_contains (OIDC_authorized_identities,
- &cache_key) )
- {
- relog_time = GNUNET_CONTAINER_multihashmap_get (
- OIDC_authorized_identities, &cache_key);
-
- current_time = GNUNET_TIME_absolute_get();
-
- GNUNET_CONTAINER_multihashmap_remove_all(OIDC_authorized_identities, &cache_key);
- // 30 min after old login -> redirect to login
- if ( current_time.abs_value_us <= relog_time->abs_value_us )
- {
- resp = GNUNET_REST_create_response ("");
+ GNUNET_SCHEDULER_add_now(&login_check,handle);
+ return;
+ }
- GNUNET_CRYPTO_ecdsa_public_key_from_string (identity_cookie,
- strlen (identity_cookie),
- &pubkey);
+ GNUNET_SCHEDULER_add_now(&login_redirection,handle);
+}
- // iterate over egos and compare their public key
-// GNUNET_IDENTITY_PROVIDER_get_attributes_start
- // iterate over scope variables
- char delimiter[] = " ";
- char *scope_attribute;
- scope_attribute = strtok(scope, delimiter);
- while ( NULL != scope_attribute )
- {
- if ( NULL == strstr (scope_attribute, OIDC_EXPECTED_AUTHORIZATION_SCOPE) )
- {
- // claim attribute from ego
- scope_attribute = strtok (NULL, delimiter);
- }
- }
- // create an authorization code
+/**
+ * Responds to authorization POST request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+authorize_POST_cont (struct GNUNET_REST_RequestHandle *con_handle,
+ const char* url,
+ void *cls)
+{
+ struct RequestHandle *handle = cls;
+ json_t *cache_object;
+ json_error_t error;
+ handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
-// GNUNET_IDENTITY_PROVIDER_t
+ //gets identity of login try with cookie
+ cookie_identity_interpretation(handle);
- MHD_add_response_header (resp, "Location", redirect_uri);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
- cleanup_handle (handle);
- GNUNET_free(relog_time);
- return;
- }
- GNUNET_free(relog_time);
- }
+ //RECOMMENDED value: state - REQUIRED for answers
+ cache_object = json_object_get (handle->oidc->post_object, OIDC_STATE_KEY);
+ if ( NULL != cache_object && json_is_string(cache_object) )
+ {
+ handle->oidc->state = json_string_value (cache_object);
+ handle->oidc->state = GNUNET_strdup(handle->oidc->state);
}
+ // REQUIRED value: client_id
+ cache_object = json_object_get (handle->oidc->post_object,
+ OIDC_CLIENT_ID_KEY);
+ if ( NULL == cache_object || !json_is_string(cache_object) )
+ {
+ handle->emsg = GNUNET_strdup("invalid_request");
+ handle->edesc = GNUNET_strdup("missing parameter client_id");
+ handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ handle->oidc->client_id = json_string_value (cache_object);
+ handle->oidc->client_id = GNUNET_strdup(handle->oidc->client_id);
- // login redirection
if ( GNUNET_OK
- == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
- "address", &login_base_url) )
+ != GNUNET_CRYPTO_ecdsa_public_key_from_string (
+ handle->oidc->client_id, strlen (handle->oidc->client_id),
+ &handle->oidc->client_pkey) )
{
- GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
- login_base_url,
- OIDC_RESPONSE_TYPE_KEY,
- response_type,
- OIDC_CLIENT_ID_KEY,
- client_id,
- OIDC_REDIRECT_URI_KEY,
- redirect_uri,
- OIDC_SCOPE_KEY,
- scope,
- OIDC_STATE_KEY,
- (NULL == state) ? state : "",
- OIDC_NONCE_KEY,
- (NULL == nonce) ? nonce : "");
- resp = GNUNET_REST_create_response ("");
- MHD_add_response_header (resp, "Location", new_redirect);
+ handle->emsg = GNUNET_strdup("unauthorized_client");
+ handle->edesc = GNUNET_strdup("The client is not authorized to request an "
+ "authorization code using this method.");
+ handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
}
- else
+
+ if ( NULL == handle->ego_head )
{
- handle->emsg = GNUNET_strdup("No server configuration");
+ //TODO throw error or ignore if egos are missing?
+ handle->emsg = GNUNET_strdup("server_error");
+ handle->edesc = GNUNET_strdup ("Egos are missing");
handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
GNUNET_SCHEDULER_add_now (&do_error, handle);
return;
}
- handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
- cleanup_handle (handle);
- GNUNET_free(new_redirect);
- return;
-}
+ handle->ego_entry = handle->ego_head;
+ handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
+ handle->oidc->is_client_trusted = GNUNET_NO;
+
+ // Checks if client_id is valid:
+ handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
+ handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
+ handle, &namestore_iteration_callback, handle,
+ &namestore_iteration_finished_POST, handle);
+}
/**
* Combines an identity with a login time and responds OK to login request
const char* url,
void *cls)
{
-
-
struct MHD_Response *resp = GNUNET_REST_create_response ("");
struct RequestHandle *handle = cls;
struct GNUNET_HashCode cache_key;
struct GNUNET_TIME_Absolute *current_time;
+ struct GNUNET_TIME_Absolute *last_time;
char* cookie;
json_t *root;
json_error_t error;
GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
+
current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
*current_time = GNUNET_TIME_relative_to_absolute (
GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (),
30));
+ last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
+ if (NULL != last_time)
+ {
+ GNUNET_free(last_time);
+ }
GNUNET_CONTAINER_multihashmap_put (
- OIDC_authorized_identities, &cache_key, current_time,
+ OIDC_identity_login_time, &cache_key, current_time,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
}
GNUNET_free(cookie);
json_decref (root);
- cleanup_handle (handle);
+ GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
return;
}
+static void
+token_cont(struct GNUNET_REST_RequestHandle *con_handle,
+ const char* url,
+ void *cls)
+{
+ //TODO static strings
+ struct RequestHandle *handle = cls;
+ struct GNUNET_HashCode cache_key;
+ char *authorization, *cache_authorization, *jwt;
+ char delimiter[]=" ";
+ json_t *cache_object;
+ json_error_t error;
+ char *grant_type, *code, *expected_jwt, *redirect_uri, *expected_redirect_uri;
+
+ handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
+ //Check Authorization Header
+ GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
+ &cache_key);
+ if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
+ &cache_key) )
+ {
+ //error
+ }
+ authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
+ //split JWT in "Base" and [content]
+ cache_authorization = GNUNET_strdup (authorization);
+ jwt = strtok(cache_authorization,delimiter);
+ if( NULL != jwt)
+ {
+ jwt = strtok(jwt, delimiter);
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Test:%s\n", jwt);
+ }
+
+ cache_object = json_object_get (handle->oidc->post_object, "grant_type");
+ if ( NULL == cache_object || !json_is_string(cache_object) )
+ {
+ handle->emsg=GNUNET_strdup("invalid_request");
+ handle->edesc=GNUNET_strdup("missing parameter grant_type");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ grant_type = json_string_value (cache_object);
+
+ //Check parameter grant_type == "authorization_code"
+ if (0 != strcmp("authorization_code", grant_type))
+ {
+ //error
+ }
+
+ cache_object = json_object_get (handle->oidc->post_object, "code");
+ if ( NULL == cache_object || !json_is_string(cache_object) )
+ {
+ handle->emsg=GNUNET_strdup("invalid_request");
+ handle->edesc=GNUNET_strdup("missing parameter code");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ code = json_string_value (cache_object);
+
+ // lookup code in grants_hashmap and check if [content] is same
+ GNUNET_CRYPTO_hash(code, strlen(code), &cache_key);
+ if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_grants, &cache_key) )
+ {
+ //error
+ }
+ expected_jwt = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_grants, &cache_key);
+
+ if (0 != strcmp(expected_jwt,jwt))
+ {
+ //error
+ }
+
+ cache_object = json_object_get (handle->oidc->post_object, "redirect_uri");
+ if ( NULL == cache_object || !json_is_string(cache_object) )
+ {
+ handle->emsg=GNUNET_strdup("invalid_request");
+ handle->edesc=GNUNET_strdup("missing parameter code");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ redirect_uri = json_string_value (cache_object);
+
+ // check redirect_uri
+ // jwt breakdown to iss or sub
+
+// GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", iss);
+// // verify the redirect uri matches https://<client_id>.zkey[/xyz]
+// if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
+// {
+// handle->emsg=GNUNET_strdup("invalid_request");
+// handle->edesc=GNUNET_strdup("Invalid redirect_uri");
+// GNUNET_SCHEDULER_add_now (&do_error, handle);
+// GNUNET_free(expected_redirect_uri);
+// return;
+// }
+// handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
+// GNUNET_free(expected_redirect_uri);
+
+
+ //do we need the client_id?
+
+ GNUNET_free(cache_authorization);
+ decref(handle->oidc->post_object);
+}
+
/**
* Handle rest request
*
{MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
{MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
- {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_get_cont},
+ {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_GET_cont},
+ {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_POST_cont},
{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
- {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_post_cont},
+ {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_cont},
{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
{MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
void *proc_cls)
{
struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
- if ( NULL == OIDC_authorized_identities )
- {
- OIDC_authorized_identities = GNUNET_CONTAINER_multihashmap_create (10,
- GNUNET_NO);
- }
+ handle->oidc = GNUNET_new (struct OIDC_Variables);
+ if ( NULL == OIDC_identity_login_time )
+ OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+ if ( NULL == OIDC_identity_grants )
+ OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+ handle->response_code = 0;
handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
handle->proc_cls = proc_cls;
handle->proc = proc;
handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
&list_ego,
handle);
+ handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
handle->timeout_task =
GNUNET_SCHEDULER_add_delayed (handle->timeout,
&do_timeout,
{
struct GNUNET_REST_Plugin *api = cls;
struct Plugin *plugin = api->cls;
-
plugin->cfg = NULL;
+
+ struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
+ void *value = NULL;
+ hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
+ OIDC_identity_login_time);
+ while (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
+ {
+ if (NULL != value)
+ GNUNET_free(value);
+ }
+ GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
+ hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
+ while (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
+ {
+ if (NULL != value)
+ GNUNET_free(value);
+ }
+ GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
GNUNET_free_non_null (allow_methods);
GNUNET_free (api);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,