static void on_jwt_verification_done(grpc_exec_ctx *exec_ctx, void *user_data, grpc_jwt_verifier_status status, grpc_jwt_claims *claims) { synchronizer *sync = user_data; sync->success = (status == GRPC_JWT_VERIFIER_OK); if (sync->success) { char *claims_str; GPR_ASSERT(claims != NULL); claims_str = grpc_json_dump_to_string((grpc_json *)grpc_jwt_claims_json(claims), 2); printf("Claims: \n\n%s\n", claims_str); gpr_free(claims_str); grpc_jwt_claims_destroy(exec_ctx, claims); } else { GPR_ASSERT(claims == NULL); fprintf(stderr, "Verification failed with error %s\n", grpc_jwt_verifier_status_to_string(status)); } gpr_mu_lock(sync->mu); sync->is_done = 1; GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(sync->pollset, NULL)); gpr_mu_unlock(sync->mu); }
void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) { if (ctx->audience != NULL) gpr_free(ctx->audience); if (ctx->claims != NULL) grpc_jwt_claims_destroy(ctx->claims); gpr_slice_unref(ctx->signature); gpr_slice_unref(ctx->signed_data); jose_header_destroy(ctx->header); /* TODO: see what to do with claims... */ gpr_free(ctx); }
static void on_verification_success(void *user_data, grpc_jwt_verifier_status status, grpc_jwt_claims *claims) { GPR_ASSERT(status == GRPC_JWT_VERIFIER_OK); GPR_ASSERT(claims != NULL); GPR_ASSERT(user_data == (void *)expected_user_data); GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), expected_audience) == 0); grpc_jwt_claims_destroy(claims); }
void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) { if (ctx->audience != NULL) gpr_free(ctx->audience); if (ctx->claims != NULL) grpc_jwt_claims_destroy(ctx->claims); grpc_slice_unref(ctx->signature); grpc_slice_unref(ctx->signed_data); jose_header_destroy(ctx->header); for (size_t i = 0; i < HTTP_RESPONSE_COUNT; i++) { grpc_http_response_destroy(&ctx->responses[i]); } /* TODO: see what to do with claims... */ gpr_free(ctx); }
static void test_bad_audience_claims_failure(void) { grpc_jwt_claims *claims; gpr_slice s = gpr_slice_from_copied_string(claims_without_time_constraint); grpc_json *json = grpc_json_parse_string_with_len( (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s)); GPR_ASSERT(json != NULL); claims = grpc_jwt_claims_from_json(json, s); GPR_ASSERT(claims != NULL); GPR_ASSERT(grpc_jwt_claims_check(claims, "https://bar.com") == GRPC_JWT_VERIFIER_BAD_AUDIENCE); grpc_jwt_claims_destroy(claims); }
void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, grpc_jwt_verifier *verifier, grpc_pollset *pollset, const char *jwt, const char *audience, grpc_jwt_verification_done_cb cb, void *user_data) { const char *dot = NULL; grpc_json *json; jose_header *header = NULL; grpc_jwt_claims *claims = NULL; grpc_slice header_buffer; grpc_slice claims_buffer; grpc_slice signature; size_t signed_jwt_len; const char *cur = jwt; GPR_ASSERT(verifier != NULL && jwt != NULL && audience != NULL && cb != NULL); dot = strchr(cur, '.'); if (dot == NULL) goto error; json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &header_buffer); if (json == NULL) goto error; header = jose_header_from_json(json, header_buffer); if (header == NULL) goto error; cur = dot + 1; dot = strchr(cur, '.'); if (dot == NULL) goto error; json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &claims_buffer); if (json == NULL) goto error; claims = grpc_jwt_claims_from_json(json, claims_buffer); if (claims == NULL) goto error; signed_jwt_len = (size_t)(dot - jwt); cur = dot + 1; signature = grpc_base64_decode(cur, 1); if (GRPC_SLICE_IS_EMPTY(signature)) goto error; retrieve_key_and_verify( exec_ctx, verifier_cb_ctx_create(verifier, pollset, header, claims, audience, signature, jwt, signed_jwt_len, user_data, cb)); return; error: if (header != NULL) jose_header_destroy(header); if (claims != NULL) grpc_jwt_claims_destroy(claims); cb(user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, NULL); }
static void test_claims_success(void) { grpc_jwt_claims *claims; gpr_slice s = gpr_slice_from_copied_string(claims_without_time_constraint); grpc_json *json = grpc_json_parse_string_with_len( (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s)); GPR_ASSERT(json != NULL); claims = grpc_jwt_claims_from_json(json, s); GPR_ASSERT(claims != NULL); GPR_ASSERT(grpc_jwt_claims_json(claims) == json); GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), "https://foo.com") == 0); GPR_ASSERT(strcmp(grpc_jwt_claims_issuer(claims), "blah.foo.com") == 0); GPR_ASSERT(strcmp(grpc_jwt_claims_subject(claims), "*****@*****.**") == 0); GPR_ASSERT(strcmp(grpc_jwt_claims_id(claims), "jwtuniqueid") == 0); GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") == GRPC_JWT_VERIFIER_OK); grpc_jwt_claims_destroy(claims); }
/* Takes ownership of json and buffer even in case of failure. */ grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, grpc_slice buffer) { grpc_json *cur; grpc_jwt_claims *claims = gpr_malloc(sizeof(grpc_jwt_claims)); memset(claims, 0, sizeof(grpc_jwt_claims)); claims->json = json; claims->buffer = buffer; claims->iat = gpr_inf_past(GPR_CLOCK_REALTIME); claims->nbf = gpr_inf_past(GPR_CLOCK_REALTIME); claims->exp = gpr_inf_future(GPR_CLOCK_REALTIME); /* Per the spec, all fields are optional. */ for (cur = json->child; cur != NULL; cur = cur->next) { if (strcmp(cur->key, "sub") == 0) { claims->sub = validate_string_field(cur, "sub"); if (claims->sub == NULL) goto error; } else if (strcmp(cur->key, "iss") == 0) { claims->iss = validate_string_field(cur, "iss"); if (claims->iss == NULL) goto error; } else if (strcmp(cur->key, "aud") == 0) { claims->aud = validate_string_field(cur, "aud"); if (claims->aud == NULL) goto error; } else if (strcmp(cur->key, "jti") == 0) { claims->jti = validate_string_field(cur, "jti"); if (claims->jti == NULL) goto error; } else if (strcmp(cur->key, "iat") == 0) { claims->iat = validate_time_field(cur, "iat"); if (gpr_time_cmp(claims->iat, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) goto error; } else if (strcmp(cur->key, "exp") == 0) { claims->exp = validate_time_field(cur, "exp"); if (gpr_time_cmp(claims->exp, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) goto error; } else if (strcmp(cur->key, "nbf") == 0) { claims->nbf = validate_time_field(cur, "nbf"); if (gpr_time_cmp(claims->nbf, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) goto error; } } return claims; error: grpc_jwt_claims_destroy(claims); return NULL; }
static void test_expired_claims_failure(void) { grpc_jwt_claims *claims; gpr_slice s = gpr_slice_from_copied_string(expired_claims); grpc_json *json = grpc_json_parse_string_with_len( (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s)); gpr_timespec exp_iat = {100, 0, GPR_CLOCK_REALTIME}; gpr_timespec exp_exp = {120, 0, GPR_CLOCK_REALTIME}; gpr_timespec exp_nbf = {60, 0, GPR_CLOCK_REALTIME}; GPR_ASSERT(json != NULL); claims = grpc_jwt_claims_from_json(json, s); GPR_ASSERT(claims != NULL); GPR_ASSERT(grpc_jwt_claims_json(claims) == json); GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), "https://foo.com") == 0); GPR_ASSERT(strcmp(grpc_jwt_claims_issuer(claims), "blah.foo.com") == 0); GPR_ASSERT(strcmp(grpc_jwt_claims_subject(claims), "*****@*****.**") == 0); GPR_ASSERT(strcmp(grpc_jwt_claims_id(claims), "jwtuniqueid") == 0); GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_issued_at(claims), exp_iat) == 0); GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_expires_at(claims), exp_exp) == 0); GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_not_before(claims), exp_nbf) == 0); GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") == GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE); grpc_jwt_claims_destroy(claims); }