Skip to content

Commit

Permalink
Merge pull request grpc#641 from jboeuf/jwt_id_token
Browse files Browse the repository at this point in the history
Implementing JWT credentials (a.k.a JWT ID Tokens).
  • Loading branch information
yang-g committed Feb 21, 2015
2 parents 7db49ff + 25380de commit c5b9692
Show file tree
Hide file tree
Showing 15 changed files with 570 additions and 71 deletions.
34 changes: 33 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ grpc_completion_queue_benchmark: $(BINDIR)/$(CONFIG)/grpc_completion_queue_bench
grpc_completion_queue_test: $(BINDIR)/$(CONFIG)/grpc_completion_queue_test
grpc_credentials_test: $(BINDIR)/$(CONFIG)/grpc_credentials_test
grpc_fetch_oauth2: $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2
grpc_create_jwt: $(BINDIR)/$(CONFIG)/grpc_create_jwt
grpc_json_token_test: $(BINDIR)/$(CONFIG)/grpc_json_token_test
grpc_stream_op_test: $(BINDIR)/$(CONFIG)/grpc_stream_op_test
hpack_parser_test: $(BINDIR)/$(CONFIG)/hpack_parser_test
Expand Down Expand Up @@ -1762,7 +1763,7 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/thread_pool_test || ( echo test thread_pool_test failed ; exit 1 )


tools: privatelibs $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2
tools: privatelibs $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 $(BINDIR)/$(CONFIG)/grpc_create_jwt

buildbenchmarks: privatelibs $(BINDIR)/$(CONFIG)/grpc_completion_queue_benchmark $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark

Expand Down Expand Up @@ -6478,6 +6479,37 @@ endif
endif


GRPC_CREATE_JWT_SRC = \
test/core/security/create_jwt.c \

GRPC_CREATE_JWT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CREATE_JWT_SRC))))

ifeq ($(NO_SECURE),true)

# You can't build secure targets if you don't have OpenSSL with ALPN.

$(BINDIR)/$(CONFIG)/grpc_create_jwt: openssl_dep_error

else

$(BINDIR)/$(CONFIG)/grpc_create_jwt: $(GRPC_CREATE_JWT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(GRPC_CREATE_JWT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/grpc_create_jwt

endif

$(OBJDIR)/$(CONFIG)/test/core/security/create_jwt.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a

deps_grpc_create_jwt: $(GRPC_CREATE_JWT_OBJS:.o=.dep)

ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(GRPC_CREATE_JWT_OBJS:.o=.dep)
endif
endif


GRPC_JSON_TOKEN_TEST_SRC = \
test/core/security/json_token_test.c \

Expand Down
14 changes: 14 additions & 0 deletions build.json
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,20 @@
"gpr"
]
},
{
"name": "grpc_create_jwt",
"build": "tool",
"language": "c",
"src": [
"test/core/security/create_jwt.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "grpc_json_token_test",
"build": "test",
Expand Down
8 changes: 8 additions & 0 deletions include/grpc/grpc_security.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ extern const gpr_timespec grpc_max_auth_token_lifetime;
grpc_credentials *grpc_service_account_credentials_create(
const char *json_key, const char *scope, gpr_timespec token_lifetime);

/* Creates a JWT credentials object. May return NULL if the input is invalid.
- json_key is the JSON key string containing the client's private key.
- token_lifetime is the lifetime of each Json Web Token (JWT) created with
this credentials. It should not exceed grpc_max_auth_token_lifetime or
will be cropped to this value. */
grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
gpr_timespec token_lifetime);

/* Creates a fake transport security credentials object for testing. */
grpc_credentials *grpc_fake_transport_security_credentials_create(void);

Expand Down
32 changes: 31 additions & 1 deletion src/core/security/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
typedef struct {
grpc_credentials *creds;
grpc_mdstr *host;
grpc_mdstr *method;
grpc_call_op op;
} call_data;

Expand All @@ -56,6 +57,7 @@ typedef struct {
grpc_channel_security_context *security_context;
grpc_mdctx *md_ctx;
grpc_mdstr *authority_string;
grpc_mdstr *path_string;
grpc_mdstr *error_msg_key;
} channel_data;

Expand Down Expand Up @@ -89,6 +91,26 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems,
grpc_call_next_op(elem, &((call_data *)elem->call_data)->op);
}

static char *build_service_url(const char *url_scheme, call_data *calld) {
char *service_url;
char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
char *last_slash = strrchr(service, '/');
if (last_slash == NULL) {
gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
service[0] = '\0';
} else if (last_slash == service) {
/* No service part in fully qualified method name: will just be "/". */
service[1] = '\0';
} else {
*last_slash = '\0';
}
if (url_scheme == NULL) url_scheme = "";
gpr_asprintf(&service_url, "%s://%s%s", url_scheme,
grpc_mdstr_as_c_string(calld->host), service);
gpr_free(service);
return service_url;
}

static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
Expand All @@ -106,9 +128,12 @@ static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
}
if (channel_creds != NULL &&
grpc_credentials_has_request_metadata(channel_creds)) {
char *service_url =
build_service_url(channeld->security_context->base.url_scheme, calld);
calld->op = *op; /* Copy op (originates from the caller's stack). */
grpc_credentials_get_request_metadata(channel_creds,
grpc_credentials_get_request_metadata(channel_creds, service_url,
on_credentials_metadata, elem);
gpr_free(service_url);
} else {
grpc_call_next_op(elem, op);
}
Expand Down Expand Up @@ -146,6 +171,9 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
if (op->data.metadata->key == channeld->authority_string) {
if (calld->host != NULL) grpc_mdstr_unref(calld->host);
calld->host = grpc_mdstr_ref(op->data.metadata->value);
} else if (op->data.metadata->key == channeld->path_string) {
if (calld->method != NULL) grpc_mdstr_unref(calld->method);
calld->method = grpc_mdstr_ref(op->data.metadata->value);
}
grpc_call_next_op(elem, op);
break;
Expand Down Expand Up @@ -194,6 +222,7 @@ static void init_call_elem(grpc_call_element *elem,
call_data *calld = elem->call_data;
calld->creds = NULL;
calld->host = NULL;
calld->method = NULL;
}

/* Destructor for call_data */
Expand Down Expand Up @@ -230,6 +259,7 @@ static void init_channel_elem(grpc_channel_element *elem,
channeld->md_ctx = metadata_context;
channeld->authority_string =
grpc_mdstr_from_string(channeld->md_ctx, ":authority");
channeld->path_string = grpc_mdstr_from_string(channeld->md_ctx, ":path");
channeld->error_msg_key =
grpc_mdstr_from_string(channeld->md_ctx, "grpc-message");
}
Expand Down
Loading

0 comments on commit c5b9692

Please sign in to comment.