API for auth context and server-side secure transport only impl.

Still TODO:
- a way to plug a metadata processing (somewhat elsewhere but did not
  one to overload this already large PR).
- plug-in the auth context on the client side.
- Better end to end testing.
pull/1672/head
Julien Boeuf 10 years ago
parent c6f8d0a4c6
commit 84d964a8df
  1. 34
      Makefile
  2. 14
      build.json
  3. 49
      include/grpc/grpc_security.h
  4. 2
      src/core/security/client_auth_filter.c
  5. 74
      src/core/security/security_connector.c
  6. 1
      src/core/security/security_connector.h
  7. 150
      src/core/security/security_context.c
  8. 54
      src/core/security/security_context.h
  9. 50
      src/core/security/server_auth_filter.c
  10. 27
      test/core/end2end/tests/request_response_with_payload_and_call_creds.c
  11. 156
      test/core/security/auth_context_test.c
  12. 9
      tools/run_tests/tests.json
  13. 9
      vsprojects/Grpc.mak

File diff suppressed because one or more lines are too long

@ -1267,6 +1267,20 @@
"gpr"
]
},
{
"name": "grpc_auth_context_test",
"build": "test",
"language": "c",
"src": [
"test/core/security/auth_context_test.c"
],
"deps": [
"grpc_test_util",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "grpc_base64_test",
"build": "test",

@ -191,6 +191,55 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
grpc_call_error grpc_call_set_credentials(grpc_call *call,
grpc_credentials *creds);
/* --- Authentication Context. --- */
/* TODO(jboeuf): Define some well-known property names. */
#define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME \
"transport_security_type"
#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake"
#define GRPC_SSL_TRANSPORT_SECURITY_TYPE "ssl"
#define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"
#define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name"
typedef struct grpc_auth_context grpc_auth_context;
typedef struct grpc_auth_property_iterator grpc_auth_property_iterator;
/* value, if not NULL, is guaranteed to be NULL terminated. */
typedef struct grpc_auth_property {
char *name;
char *value;
size_t value_length;
} grpc_auth_property;
/* Returns NULL when the iterator is at the end. */
const grpc_auth_property *grpc_auth_property_iterator_next(
grpc_auth_property_iterator *it);
void grpc_auth_property_iterator_destroy(grpc_auth_property_iterator *it);
grpc_auth_property_iterator *grpc_auth_context_property_iterator(
const grpc_auth_context *ctx);
/* Gets the peer identity. Returns NULL if the peer is not authenticated.
An identity may consist of multiple values (e.g. Subject Alternative Names
in X509 SSL certificates). */
grpc_auth_property_iterator *grpc_auth_context_peer_identity(
const grpc_auth_context *ctx);
/* Finds a property in the context. May return an empty iterator if no property
with this name was found in the context. Will return NULL on NULL input. */
grpc_auth_property_iterator *grpc_auth_context_find_properties_by_name(
const grpc_auth_context *ctx, const char *name);
/* Gets the name of the property that indicates the peer identity. Will return
NULL if the peer is not authenticated. */
const char *grpc_auth_context_peer_identity_property_name(
const grpc_auth_context *ctx);
/* Gets the auth context from the call. */
const grpc_auth_context *grpc_call_auth_context(grpc_call *call);
#ifdef __cplusplus
}
#endif

@ -189,6 +189,8 @@ static void auth_start_transport_op(grpc_call_element *elem,
grpc_linked_mdelem *l;
size_t i;
/* TODO(jboeuf): write the call auth context. */
if (op->send_ops && !calld->sent_initial_metadata) {
size_t nops = op->send_ops->nops;
grpc_stream_op *ops = op->send_ops->ops;

@ -37,6 +37,7 @@
#include "src/core/security/credentials.h"
#include "src/core/security/secure_endpoint.h"
#include "src/core/security/security_context.h"
#include "src/core/support/env.h"
#include "src/core/support/file.h"
#include "src/core/support/string.h"
@ -194,10 +195,14 @@ typedef struct {
static void fake_channel_destroy(grpc_security_connector *sc) {
grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
grpc_credentials_unref(c->request_metadata_creds);
grpc_auth_context_unref(sc->auth_context);
gpr_free(sc);
}
static void fake_server_destroy(grpc_security_connector *sc) { gpr_free(sc); }
static void fake_server_destroy(grpc_security_connector *sc) {
grpc_auth_context_unref(sc->auth_context);
gpr_free(sc);
}
static grpc_security_status fake_channel_create_handshaker(
grpc_security_connector *sc, tsi_handshaker **handshaker) {
@ -236,6 +241,12 @@ static grpc_security_status fake_check_peer(grpc_security_connector *sc,
status = GRPC_SECURITY_ERROR;
goto end;
}
grpc_auth_context_unref(sc->auth_context);
sc->auth_context = grpc_auth_context_create(NULL, 1);
sc->auth_context->properties[0] = grpc_auth_property_init_from_cstring(
GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
end:
tsi_peer_destruct(&peer);
return status;
@ -264,6 +275,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
grpc_credentials *request_metadata_creds, int call_host_check_is_async) {
grpc_fake_channel_security_connector *c =
gpr_malloc(sizeof(grpc_fake_channel_security_connector));
memset(c, 0, sizeof(grpc_fake_channel_security_connector));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.is_client_side = 1;
c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
@ -277,6 +289,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
grpc_security_connector *grpc_fake_server_security_connector_create(void) {
grpc_security_connector *c = gpr_malloc(sizeof(grpc_security_connector));
memset(c, 0, sizeof(grpc_security_connector));
gpr_ref_init(&c->refcount, 1);
c->is_client_side = 0;
c->vtable = &fake_server_vtable;
@ -309,6 +322,7 @@ static void ssl_channel_destroy(grpc_security_connector *sc) {
if (c->target_name != NULL) gpr_free(c->target_name);
if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
tsi_peer_destruct(&c->peer);
grpc_auth_context_unref(sc->auth_context);
gpr_free(sc);
}
@ -318,6 +332,7 @@ static void ssl_server_destroy(grpc_security_connector *sc) {
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
}
grpc_auth_context_unref(sc->auth_context);
gpr_free(sc);
}
@ -370,7 +385,51 @@ static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
return r;
}
static grpc_security_status ssl_check_peer(const char *peer_name,
static grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
/* We bet that iterating over a handful of properties twice will be faster
than having to realloc on average . */
size_t auth_prop_count = 1; /* for transport_security_type. */
size_t i;
const char *peer_identity_property_name = NULL;
grpc_auth_context *ctx = NULL;
for (i = 0; i < peer->property_count; i++) {
const tsi_peer_property *prop = &peer->properties[i];
if (prop->name == NULL) continue;
if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
auth_prop_count++;
/* If there is no subject alt name, have the CN as the identity. */
if (peer_identity_property_name == NULL) {
peer_identity_property_name = prop->name;
}
} else if (strcmp(prop->name,
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
auth_prop_count++;
peer_identity_property_name = prop->name;
}
}
ctx = grpc_auth_context_create(NULL, auth_prop_count);
ctx->properties[0] = grpc_auth_property_init_from_cstring(
GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_SSL_TRANSPORT_SECURITY_TYPE);
ctx->property_count = 1;
for (i = 0; i < peer->property_count; i++) {
const tsi_peer_property *prop = &peer->properties[i];
if (prop->name == NULL) continue;
if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
ctx->properties[ctx->property_count++] = grpc_auth_property_init(
GRPC_X509_CN_PROPERTY_NAME, prop->value.data, prop->value.length);
} else if (strcmp(prop->name,
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
ctx->properties[ctx->property_count++] = grpc_auth_property_init(
GRPC_X509_SAN_PROPERTY_NAME, prop->value.data, prop->value.length);
}
}
GPR_ASSERT(auth_prop_count == ctx->property_count);
return ctx;
}
static grpc_security_status ssl_check_peer(grpc_security_connector *sc,
const char *peer_name,
const tsi_peer *peer) {
/* Check the ALPN. */
const tsi_peer_property *p =
@ -389,7 +448,7 @@ static grpc_security_status ssl_check_peer(const char *peer_name,
gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
return GRPC_SECURITY_ERROR;
}
sc->auth_context = tsi_ssl_peer_to_auth_context(peer);
return GRPC_SECURITY_OK;
}
@ -402,9 +461,9 @@ static grpc_security_status ssl_channel_check_peer(grpc_security_connector *sc,
grpc_security_status status;
tsi_peer_destruct(&c->peer);
c->peer = peer;
status = ssl_check_peer(c->overridden_target_name != NULL
? c->overridden_target_name
: c->target_name,
status = ssl_check_peer(sc, c->overridden_target_name != NULL
? c->overridden_target_name
: c->target_name,
&peer);
return status;
}
@ -413,8 +472,7 @@ static grpc_security_status ssl_server_check_peer(grpc_security_connector *sc,
tsi_peer peer,
grpc_security_check_cb cb,
void *user_data) {
/* TODO(jboeuf): Find a way to expose the peer to the authorization layer. */
grpc_security_status status = ssl_check_peer(NULL, &peer);
grpc_security_status status = ssl_check_peer(sc, NULL, &peer);
tsi_peer_destruct(&peer);
return status;
}

@ -77,6 +77,7 @@ struct grpc_security_connector {
gpr_refcount refcount;
int is_client_side;
const char *url_scheme;
grpc_auth_context *auth_context; /* Populated after the peer is checked. */
};
/* Increments the refcount. */

@ -35,11 +35,14 @@
#include "src/core/security/security_context.h"
#include "src/core/surface/call.h"
#include "src/core/support/string.h"
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
/* --- grpc_call --- */
grpc_call_error grpc_call_set_credentials(grpc_call *call,
grpc_credentials *creds) {
grpc_client_security_context *ctx = NULL;
@ -65,6 +68,16 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call,
return GRPC_CALL_OK;
}
const grpc_auth_context *grpc_call_auth_context(grpc_call *call) {
void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY);
if (sec_ctx == NULL) return NULL;
return grpc_call_is_client(call)
? ((grpc_client_security_context *)sec_ctx)->auth_context
: ((grpc_server_security_context *)sec_ctx)->auth_context;
}
/* --- grpc_client_security_context --- */
grpc_client_security_context *grpc_client_security_context_create(void) {
grpc_client_security_context *ctx =
gpr_malloc(sizeof(grpc_client_security_context));
@ -75,5 +88,142 @@ grpc_client_security_context *grpc_client_security_context_create(void) {
void grpc_client_security_context_destroy(void *ctx) {
grpc_client_security_context *c = (grpc_client_security_context *)ctx;
grpc_credentials_unref(c->creds);
grpc_auth_context_unref(c->auth_context);
gpr_free(ctx);
}
/* --- grpc_server_security_context --- */
grpc_server_security_context *grpc_server_security_context_create(void) {
grpc_server_security_context *ctx =
gpr_malloc(sizeof(grpc_server_security_context));
memset(ctx, 0, sizeof(grpc_server_security_context));
return ctx;
}
void grpc_server_security_context_destroy(void *ctx) {
grpc_server_security_context *c = (grpc_server_security_context *)ctx;
grpc_auth_context_unref(c->auth_context);
gpr_free(ctx);
}
/* --- grpc_auth_context --- */
grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained,
size_t property_count) {
grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context));
memset(ctx, 0, sizeof(grpc_auth_context));
ctx->properties = gpr_malloc(property_count * sizeof(grpc_auth_property));
memset(ctx->properties, 0, property_count * sizeof(grpc_auth_property));
ctx->property_count = property_count;
gpr_ref_init(&ctx->refcount, 1);
if (chained != NULL) ctx->chained = grpc_auth_context_ref(chained);
return ctx;
}
grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx) {
if (ctx == NULL) return NULL;
gpr_ref(&ctx->refcount);
return ctx;
}
void grpc_auth_context_unref(grpc_auth_context *ctx) {
if (ctx == NULL) return;
if (gpr_unref(&ctx->refcount)) {
size_t i;
grpc_auth_context_unref(ctx->chained);
if (ctx->properties != NULL) {
for (i = 0; i < ctx->property_count; i++) {
grpc_auth_property_reset(&ctx->properties[i]);
}
gpr_free(ctx->properties);
}
}
}
const char *grpc_auth_context_peer_identity_property_name(
const grpc_auth_context *ctx) {
return ctx->peer_identity_property_name;
}
grpc_auth_property_iterator *grpc_auth_context_property_iterator(
const grpc_auth_context *ctx) {
grpc_auth_property_iterator *it;
if (ctx == NULL) return NULL;
it = gpr_malloc(sizeof(grpc_auth_property_iterator));
memset(it, 0, sizeof(grpc_auth_property_iterator));
it->ctx = ctx;
return it;
}
const grpc_auth_property *grpc_auth_property_iterator_next(
grpc_auth_property_iterator *it) {
if (it == NULL) return NULL;
while (it->index == it->ctx->property_count) {
if (it->ctx->chained == NULL) return NULL;
it->ctx = it->ctx->chained;
it->index = 0;
}
if (it->name == NULL) {
return &it->ctx->properties[it->index++];
} else {
while (it->index < it->ctx->property_count) {
const grpc_auth_property *prop = &it->ctx->properties[it->index++];
GPR_ASSERT(prop->name != NULL);
if (strcmp(it->name, prop->name) == 0) {
return prop;
}
}
/* We could not find the name, try another round. */
return grpc_auth_property_iterator_next(it);
}
}
grpc_auth_property_iterator *grpc_auth_context_find_properties_by_name(
const grpc_auth_context *ctx, const char *name) {
grpc_auth_property_iterator *it;
if (ctx == NULL || name == NULL) return NULL;
it = grpc_auth_context_property_iterator(ctx);
it->name = gpr_strdup(name);
return it;
}
grpc_auth_property_iterator *grpc_auth_context_peer_identity(
const grpc_auth_context *ctx) {
if (ctx == NULL || ctx->peer_identity_property_name == NULL) return NULL;
return grpc_auth_context_find_properties_by_name(
ctx, ctx->peer_identity_property_name);
}
void grpc_auth_property_iterator_destroy(grpc_auth_property_iterator *it) {
if (it == NULL) return;
if (it->name != NULL) gpr_free(it->name);
gpr_free(it);
}
grpc_auth_property grpc_auth_property_init_from_cstring(const char *name,
const char *value) {
grpc_auth_property prop;
prop.name = gpr_strdup(name);
prop.value = gpr_strdup(value);
prop.value_length = strlen(value);
return prop;
}
grpc_auth_property grpc_auth_property_init(const char *name, const char *value,
size_t value_length) {
grpc_auth_property prop;
prop.name = gpr_strdup(name);
prop.value = gpr_malloc(value_length + 1);
memcpy(prop.value, value, value_length);
prop.value[value_length] = '\0';
prop.value_length = value_length;
return prop;
}
void grpc_auth_property_reset(grpc_auth_property *property) {
if (property->name != NULL) gpr_free(property->name);
if (property->value != NULL) gpr_free(property->value);
memset(property, 0, sizeof(grpc_auth_property));
}

@ -36,13 +36,65 @@
#include "src/core/security/credentials.h"
/* Security context attached to a client-side call. */
/* --- grpc_auth_context ---
High level authentication context object. Can optionally be chained. */
/* Property names are always NULL terminated. */
struct grpc_auth_property_iterator {
const grpc_auth_context *ctx;
size_t index;
char *name;
};
struct grpc_auth_context {
struct grpc_auth_context *chained;
grpc_auth_property *properties;
size_t property_count;
gpr_refcount refcount;
const char *peer_identity_property_name;
};
/* Constructor. */
grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained,
size_t property_count);
/* Refcounting. */
grpc_auth_context *grpc_auth_context_ref(
grpc_auth_context *ctx);
void grpc_auth_context_unref(grpc_auth_context *ctx);
grpc_auth_property grpc_auth_property_init_from_cstring(const char *name,
const char *value);
grpc_auth_property grpc_auth_property_init(const char *name, const char *value,
size_t value_length);
void grpc_auth_property_reset(grpc_auth_property *property);
/* --- grpc_client_security_context ---
Internal client-side security context. */
typedef struct {
grpc_credentials *creds;
grpc_auth_context *auth_context;
} grpc_client_security_context;
grpc_client_security_context *grpc_client_security_context_create(void);
void grpc_client_security_context_destroy(void *ctx);
/* --- grpc_server_security_context ---
Internal server-side security context. */
typedef struct {
grpc_auth_context *auth_context;
} grpc_server_security_context;
grpc_server_security_context *grpc_server_security_context_create(void);
void grpc_server_security_context_destroy(void *ctx);
#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */

@ -33,6 +33,7 @@
#include "src/core/security/auth_filters.h"
#include "src/core/security/security_connector.h"
#include "src/core/security/security_context.h"
#include <grpc/support/log.h>
@ -44,20 +45,6 @@ typedef struct channel_data {
grpc_security_connector *security_connector;
} channel_data;
/* used to silence 'variable not used' warnings */
static void ignore_unused(void *ignored) {}
static void noop_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
ignore_unused(calld);
ignore_unused(chand);
/* do nothing */
}
/* Called either:
- in response to an API call (or similar) from above, to send something
- a network event (or similar) from below, to receive something
@ -65,7 +52,7 @@ static void noop_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
that is being sent or received. */
static void auth_start_transport_op(grpc_call_element *elem,
grpc_transport_op *op) {
noop_mutate_op(elem, op);
/* TODO(jboeuf): Get the metadata and get a new context from it. */
/* pass control down the stack */
grpc_call_next_op(elem, op);
@ -75,17 +62,7 @@ static void auth_start_transport_op(grpc_call_element *elem,
calls on the server */
static void channel_op(grpc_channel_element *elem,
grpc_channel_element *from_elem, grpc_channel_op *op) {
/* grab pointers to our data from the channel element */
channel_data *chand = elem->channel_data;
ignore_unused(chand);
switch (op->type) {
default:
/* pass control up or down the stack depending on op->dir */
grpc_channel_next_op(elem, op);
break;
}
grpc_channel_next_op(elem, op);
}
/* Constructor for call_data */
@ -94,21 +71,28 @@ static void init_call_elem(grpc_call_element *elem,
grpc_transport_op *initial_op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_server_security_context *server_ctx = NULL;
/* initialize members */
calld->unused = 0;
if (initial_op) noop_mutate_op(elem, initial_op);
GPR_ASSERT(initial_op && initial_op->contexts != NULL &&
chand->security_connector->auth_context != NULL &&
initial_op->contexts[GRPC_CONTEXT_SECURITY].value == NULL);
/* Create a security context for the call and reference the auth context from
the channel. */
server_ctx = grpc_server_security_context_create();
server_ctx->auth_context =
grpc_auth_context_ref(chand->security_connector->auth_context);
initial_op->contexts[GRPC_CONTEXT_SECURITY].value = server_ctx;
initial_op->contexts[GRPC_CONTEXT_SECURITY].destroy =
grpc_server_security_context_destroy;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
ignore_unused(calld);
ignore_unused(chand);
}
/* Constructor for channel_data */

@ -111,6 +111,27 @@ static void end_test(grpc_end2end_test_fixture *f) {
grpc_completion_queue_destroy(f->client_cq);
}
static void print_auth_context(int is_client, const grpc_auth_context *ctx) {
const grpc_auth_property *p;
grpc_auth_property_iterator *it;
gpr_log(GPR_INFO, "%s peer:", is_client ? "client" : "server");
it = grpc_auth_context_peer_identity(ctx);
gpr_log(GPR_INFO, "\tauthenticated: %s", it != NULL ? "YES" : "NO");
if (it != NULL) {
while ((p = grpc_auth_property_iterator_next(it)) != NULL) {
gpr_log(GPR_INFO, "\t\t%s: %s", p->name, p->value);
}
grpc_auth_property_iterator_destroy(it);
}
gpr_log(GPR_INFO, "\tall properties:");
it = grpc_auth_context_property_iterator(ctx);
GPR_ASSERT(it != NULL);
while ((p = grpc_auth_property_iterator_next(it)) != NULL) {
gpr_log(GPR_INFO, "\t\t%s: %s", p->name, p->value);
}
grpc_auth_property_iterator_destroy(it);
}
static void test_call_creds_failure(grpc_end2end_test_config config) {
grpc_call *c;
grpc_credentials *creds = NULL;
@ -158,6 +179,7 @@ static void request_response_with_payload_and_call_creds(
size_t details_capacity = 0;
int was_cancelled = 2;
grpc_credentials *creds = NULL;
const grpc_auth_context *s_auth_context = NULL;
c = grpc_channel_create_call(f.client, f.client_cq, "/foo",
"foo.test.google.fr", deadline);
@ -212,10 +234,13 @@ static void request_response_with_payload_and_call_creds(
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(f.server, &s,
&call_details,
&request_metadata_recv,
f.server_cq, f.server_cq,
f.server_cq, f.server_cq,
tag(101)));
cq_expect_completion(v_server, tag(101), 1);
cq_verify(v_server);
s_auth_context = grpc_call_auth_context(s);
GPR_ASSERT(s_auth_context != NULL);
print_auth_context(0, s_auth_context);
/* Cannot set creds on the server call object. */
GPR_ASSERT(grpc_call_set_credentials(s, NULL) != GRPC_CALL_OK);

@ -0,0 +1,156 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include<string.h>
#include "src/core/security/security_context.h"
#include "src/core/support/string.h"
#include "test/core/util/test_config.h"
#include <grpc/support/log.h>
static void test_empty_context(void) {
grpc_auth_context *ctx = grpc_auth_context_create(NULL, 0);
grpc_auth_property_iterator *it;
gpr_log(GPR_INFO, __FUNCTION__);
GPR_ASSERT(ctx != NULL);
GPR_ASSERT(grpc_auth_context_peer_identity_property_name(ctx) == NULL);
GPR_ASSERT(grpc_auth_context_peer_identity(ctx) == NULL);
it = grpc_auth_context_property_iterator(ctx);
GPR_ASSERT(it != NULL);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == NULL);
grpc_auth_property_iterator_destroy(it);
it = grpc_auth_context_find_properties_by_name(ctx, "foo");
GPR_ASSERT(it != NULL);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == NULL);
grpc_auth_property_iterator_destroy(it);
grpc_auth_context_unref(ctx);
}
static void test_simple_context(void) {
grpc_auth_context *ctx = grpc_auth_context_create(NULL, 3);
grpc_auth_property_iterator *it;
size_t i;
gpr_log(GPR_INFO, __FUNCTION__);
GPR_ASSERT(ctx != NULL);
GPR_ASSERT(ctx->property_count == 3);
ctx->properties[0] = grpc_auth_property_init_from_cstring("name", "chapi");
ctx->properties[1] = grpc_auth_property_init_from_cstring("name", "chapo");
ctx->properties[2] = grpc_auth_property_init_from_cstring("foo", "bar");
ctx->peer_identity_property_name = ctx->properties[0].name;
GPR_ASSERT(
strcmp(grpc_auth_context_peer_identity_property_name(ctx), "name") == 0);
it = grpc_auth_context_property_iterator(ctx);
for (i = 0; i < ctx->property_count; i++) {
const grpc_auth_property *p = grpc_auth_property_iterator_next(it);
GPR_ASSERT(p == &ctx->properties[i]);
}
GPR_ASSERT(grpc_auth_property_iterator_next(it) == NULL);
grpc_auth_property_iterator_destroy(it);
it = grpc_auth_context_find_properties_by_name(ctx, "foo");
GPR_ASSERT(it != NULL);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == &ctx->properties[2]);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == NULL);
grpc_auth_property_iterator_destroy(it);
it = grpc_auth_context_peer_identity(ctx);
GPR_ASSERT(it != NULL);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == &ctx->properties[0]);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == &ctx->properties[1]);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == NULL);
grpc_auth_property_iterator_destroy(it);
grpc_auth_context_unref(ctx);
}
static void test_chained_context(void) {
grpc_auth_context *chained = grpc_auth_context_create(NULL, 2);
grpc_auth_context *ctx = grpc_auth_context_create(chained, 3);
grpc_auth_property_iterator *it;
size_t i;
gpr_log(GPR_INFO, __FUNCTION__);
grpc_auth_context_unref(chained);
chained->properties[0] =
grpc_auth_property_init_from_cstring("name", "padapo");
chained->properties[1] = grpc_auth_property_init_from_cstring("foo", "baz");
ctx->properties[0] = grpc_auth_property_init_from_cstring("name", "chapi");
ctx->properties[1] = grpc_auth_property_init_from_cstring("name", "chapo");
ctx->properties[2] = grpc_auth_property_init_from_cstring("foo", "bar");
ctx->peer_identity_property_name = ctx->properties[0].name;
GPR_ASSERT(
strcmp(grpc_auth_context_peer_identity_property_name(ctx), "name") == 0);
it = grpc_auth_context_property_iterator(ctx);
for (i = 0; i < ctx->property_count; i++) {
const grpc_auth_property *p = grpc_auth_property_iterator_next(it);
GPR_ASSERT(p == &ctx->properties[i]);
}
for (i = 0; i < chained->property_count; i++) {
const grpc_auth_property *p = grpc_auth_property_iterator_next(it);
GPR_ASSERT(p == &chained->properties[i]);
}
GPR_ASSERT(grpc_auth_property_iterator_next(it) == NULL);
grpc_auth_property_iterator_destroy(it);
it = grpc_auth_context_find_properties_by_name(ctx, "foo");
GPR_ASSERT(it != NULL);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == &ctx->properties[2]);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == &chained->properties[1]);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == NULL);
grpc_auth_property_iterator_destroy(it);
it = grpc_auth_context_peer_identity(ctx);
GPR_ASSERT(it != NULL);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == &ctx->properties[0]);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == &ctx->properties[1]);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == &chained->properties[0]);
GPR_ASSERT(grpc_auth_property_iterator_next(it) == NULL);
grpc_auth_property_iterator_destroy(it);
grpc_auth_context_unref(ctx);
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_empty_context();
test_simple_context();
test_chained_context();
return 0;
}

@ -312,6 +312,15 @@
"posix"
]
},
{
"flaky": false,
"language": "c",
"name": "grpc_auth_context_test",
"platforms": [
"windows",
"posix"
]
},
{
"flaky": false,
"language": "c",

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save