Skip to content

Commit 529e63a

Browse files
author
Michal Witkowski
committedDec 18, 2016
add validator docs and regen auth readme
1 parent 45ab1ff commit 529e63a

File tree

6 files changed

+213
-21
lines changed

6 files changed

+213
-21
lines changed
 

‎auth/README.md

+84-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,86 @@
1-
# gRPC Auth Interceptor
1+
# grpc_auth
2+
--
3+
import "github.com/mwitkow/go-grpc-middleware/auth"
24

3-
Package `grpc_auther` provides an easy way to hook Bearer-token and TLS credentials authorization to your gRPC server.
5+
`grpc_auth` a generic server-side auth middleware for gRPC.
46

7+
8+
### Server Side Auth Middleware
9+
10+
It allows for easy assertion of `:authorization` headers in gRPC calls, be it
11+
HTTP Basic auth, or OAuth2 Bearer tokens.
12+
13+
The middleware takes a user-customizable `AuthFunc`, which can be customized to
14+
verify and extract auth information from the request. The extracted information
15+
can be put in the `context.Context` of handlers downstream for retrieval.
16+
17+
It also allows for per-service implementation overrides of `AuthFunc`. See
18+
`ServiceAuthFuncOverride`.
19+
20+
Please see examples for simple examples of use.
21+
22+
## Usage
23+
24+
#### func AuthFromMD
25+
26+
```go
27+
func AuthFromMD(ctx context.Context, expectedScheme string) (string, error)
28+
```
29+
AuthFromMD is a helper function for extracting the :authorization header from
30+
the gRPC metadata of the request.
31+
32+
It expects the `:authorization` header to be of a certain scheme (e.g. `basic`,
33+
`bearer`), in a case-insensitive format (see rfc2617, sec 1.2). If no such
34+
authorization is found, or the token is of wrong scheme, an error with gRPC
35+
status `Unauthenticated` is returned.
36+
37+
#### func StreamServerInterceptor
38+
39+
```go
40+
func StreamServerInterceptor(authFunc AuthFunc) grpc.StreamServerInterceptor
41+
```
42+
StreamServerInterceptor returns a new unary server interceptors that performs
43+
per-request auth.
44+
45+
#### func UnaryServerInterceptor
46+
47+
```go
48+
func UnaryServerInterceptor(authFunc AuthFunc) grpc.UnaryServerInterceptor
49+
```
50+
UnaryServerInterceptor returns a new unary server interceptors that performs
51+
per-request auth.
52+
53+
#### type AuthFunc
54+
55+
```go
56+
type AuthFunc func(ctx context.Context) (context.Context, error)
57+
```
58+
59+
AuthFunc is the pluggable function that performs authentication.
60+
61+
The passed in `Context` will contain the gRPC metadata.MD object (for
62+
header-based authentication) and the peer.Peer information that can contain
63+
transport-based credentials (e.g. `credentials.AuthInfo`).
64+
65+
The returned context will be propagated to handlers, allowing user changes to
66+
`Context`. However, please make sure that the `Context` returned is a child
67+
`Context` of the one passed in.
68+
69+
If error is returned, its `grpc.Code()` will be returned to the user as well as
70+
the verbatim message. Please make sure you use `codes.Unauthenticated` (lacking
71+
auth) and `codes.PermissionDenied` (authed, but lacking perms) appropriately.
72+
73+
#### type ServiceAuthFuncOverride
74+
75+
```go
76+
type ServiceAuthFuncOverride interface {
77+
AuthFuncOverride(ctx context.Context, fullMethodName string) (context.Context, error)
78+
}
79+
```
80+
81+
ServiceAuthFuncOverride allows a given gRPC service implementation to override
82+
the global `AuthFunc`.
83+
84+
If a service implements the AuthFuncOverride method, it takes precedence over
85+
the `AuthFunc` method, and will be called instead of AuthFunc for all method
86+
invocations within that service.

‎auth/doc.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// See LICENSE for licensing terms.
33

44
/*
5-
`grpc_auth` a generic provides server-side auth middleware for gRPC.
5+
`grpc_auth` a generic server-side auth middleware for gRPC.
66
77
Server Side Auth Middleware
88

‎chain.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
)
1212

1313
// ChainUnaryServer creates a single interceptor out of a chain of many interceptors.
14+
//
1415
// Execution is done in left-to-right order, including passing of context.
1516
// For example ChainUnaryServer(one, two, three) will execute one before two before three, and three
1617
// will see context changes of one and two.
@@ -30,6 +31,7 @@ func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnarySer
3031
}
3132

3233
// ChainStreamServer creates a single interceptor out of a chain of many interceptors.
34+
//
3335
// Execution is done in left-to-right order, including passing of context.
3436
// For example ChainUnaryServer(one, two, three) will execute one before two before three.
3537
// If you want to pass context between interceptors, use WrapServerStream.
@@ -49,6 +51,7 @@ func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.Stream
4951
}
5052

5153
// ChainUnaryClient creates a single interceptor out of a chain of many interceptors.
54+
//
5255
// Execution is done in left-to-right order, including passing of context.
5356
// For example ChainUnaryClient(one, two, three) will execute one before two before three.
5457
func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryClientInterceptor {
@@ -67,6 +70,7 @@ func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryCli
6770
}
6871

6972
// ChainStreamClient creates a single interceptor out of a chain of many interceptors.
73+
//
7074
// Execution is done in left-to-right order, including passing of context.
7175
// For example ChainStreamClient(one, two, three) will execute one before two before three.
7276
func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.StreamClientInterceptor {
@@ -85,7 +89,7 @@ func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.Stream
8589
}
8690

8791
// Chain creates a single interceptor out of a chain of many interceptors.
88-
92+
//
8993
// WithUnaryServerChain is a grpc.Server config option that accepts multiple unary interceptors.
9094
// Basically syntactic sugar.
9195
func WithUnaryServerChain(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption {

‎validator/README.md

+71-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,73 @@
1-
# gRPC Validation Interceptors
1+
# grpc_validator
2+
--
3+
import "github.com/mwitkow/go-grpc-middleware/validator"
24

3-
Package `grpc_validator` provides an easy way to hook protobuf message validation as a gRPC
4-
interceptor across all your APIs.
5+
`grpc_validator` a generic request contents validator server-side middleware for
6+
gRPC.
57

6-
It primarily meant to be used with https://github.com/mwitkow/go-proto-validators, which code-gen
7-
assertions about allowed values from `.proto` files.
8+
9+
### Request Validator Middleware
10+
11+
Validating input is important, and hard. It also causes a lot of boiler plate.
12+
This middleware checks for the existance of a `Validate` method on each of the
13+
messages of a gRPC request. This includes the single request of the `Unary`
14+
calls, as well as each message of the inbound Stream calls. In case of a
15+
validation failure, a `InvalidArgument` gRPC status is returned, alongside with
16+
a description of the validation failure.
17+
18+
While it is generic, it was indented to be used with
19+
https://github.com/mwitkow/go-proto-validators, a Go protocol buffers codegen
20+
plugin that creates the `Validate` methods (including nested messages) based on
21+
declarative options in the `.proto` files themselves. For example:
22+
23+
syntax = "proto3";
24+
package validator.examples;
25+
import "github.com/mwitkow/go-proto-validators/validator.proto";
26+
27+
message InnerMessage {
28+
// some_integer can only be in range (1, 100).
29+
int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}];
30+
// some_float can only be in range (0;1).
31+
double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}];
32+
}
33+
34+
message OuterMessage {
35+
// important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax).
36+
string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}];
37+
// proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage.
38+
InnerMessage inner = 2 [(validator.field) = {msg_exists : true}];
39+
}
40+
41+
The `OuterMessage.Validate` would include validation of regexes, existance of
42+
the InnerMessage and the range values within it. The `grpc_validator` middleware
43+
would then automatically use that to check all messages processed by the server.
44+
45+
Please consult https://github.com/mwitkow/go-proto-validators for details of
46+
`protoc` invoation and other parameters of customization.
47+
48+
## Usage
49+
50+
#### func StreamServerInterceptor
51+
52+
```go
53+
func StreamServerInterceptor() grpc.StreamServerInterceptor
54+
```
55+
StreamServerInterceptor returns a new streaming server interceptors that
56+
validates incoming messages.
57+
58+
The stage at which invalid messages will be rejected with `InvalidArgument`
59+
varies based on the type of the RPC. For `ServerStream` (1:m) requests, it will
60+
happen before reaching any userspace handlers. For `ClientStream` (n:1) or
61+
`BidiStream` (n:m) RPCs, the messages will be rejected on calls to
62+
`stream.Recv()`.
63+
64+
#### func UnaryServerInterceptor
65+
66+
```go
67+
func UnaryServerInterceptor() grpc.UnaryServerInterceptor
68+
```
69+
UnaryServerInterceptor returns a new unary server interceptors that validates
70+
incoming messages.
71+
72+
Invalid messages will be rejected with `InvalidArgument` before reaching any
73+
userspace handlers.

‎validator/doc.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2016 Michal Witkowski. All Rights Reserved.
2+
// See LICENSE for licensing terms.
3+
4+
/*
5+
`grpc_validator` a generic request contents validator server-side middleware for gRPC.
6+
7+
Request Validator Middleware
8+
9+
Validating input is important, and hard. It also causes a lot of boiler plate. This middleware
10+
checks for the existance of a `Validate` method on each of the messages of a gRPC request. This
11+
includes the single request of the `Unary` calls, as well as each message of the inbound Stream calls.
12+
In case of a validation failure, a `InvalidArgument` gRPC status is returned, alongside with a
13+
description of the validation failure.
14+
15+
While it is generic, it was indented to be used with https://github.com/mwitkow/go-proto-validators,
16+
a Go protocol buffers codegen plugin that creates the `Validate` methods (including nested messages)
17+
based on declarative options in the `.proto` files themselves. For example:
18+
19+
20+
syntax = "proto3";
21+
package validator.examples;
22+
import "github.com/mwitkow/go-proto-validators/validator.proto";
23+
24+
message InnerMessage {
25+
// some_integer can only be in range (1, 100).
26+
int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}];
27+
// some_float can only be in range (0;1).
28+
double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}];
29+
}
30+
31+
message OuterMessage {
32+
// important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax).
33+
string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}];
34+
// proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage.
35+
InnerMessage inner = 2 [(validator.field) = {msg_exists : true}];
36+
}
37+
38+
The `OuterMessage.Validate` would include validation of regexes, existance of the InnerMessage and
39+
the range values within it. The `grpc_validator` middleware would then automatically use that to
40+
check all messages processed by the server.
41+
42+
Please consult https://github.com/mwitkow/go-proto-validators for details of `protoc` invoation and
43+
other parameters of customization.
44+
*/
45+
package grpc_validator

‎validator/validator.go

+7-12
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,6 @@
11
// Copyright 2016 Michal Witkowski. All Rights Reserved.
22
// See LICENSE for licensing terms.
33

4-
/*
5-
Package `grpc_validator` provides an easy way to hook protobuf message validation as a gRPC
6-
interceptor across all your APIs.
7-
8-
It primarily meant to be used with https://github.com/mwitkow/go-proto-validators, which code-gen
9-
assertions about allowed values from `.proto` files.
10-
11-
Basically this will invoke a .Validate() method on incoming message of the stream, if such method is
12-
defined. If that method returns an error, an `INVALID_ARGUMENT` gRPC status code is returned.
13-
*/
14-
154
package grpc_validator
165

176
import (
@@ -25,6 +14,8 @@ type validator interface {
2514
}
2615

2716
// UnaryServerInterceptor returns a new unary server interceptors that validates incoming messages.
17+
//
18+
// Invalid messages will be rejected with `InvalidArgument` before reaching any userspace handlers.
2819
func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
2920
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
3021
if v, ok := req.(validator); ok {
@@ -37,7 +28,11 @@ func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
3728
}
3829

3930
// StreamServerInterceptor returns a new streaming server interceptors that validates incoming messages.
40-
// The validation happens on message receives.
31+
//
32+
// The stage at which invalid messages will be rejected with `InvalidArgument` varies based on the
33+
// type of the RPC. For `ServerStream` (1:m) requests, it will happen before reaching any userspace
34+
// handlers. For `ClientStream` (n:1) or `BidiStream` (n:m) RPCs, the messages will be rejected on
35+
// calls to `stream.Recv()`.
4136
func StreamServerInterceptor() grpc.StreamServerInterceptor {
4237
return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
4338
wrapper := &recvWrapper{stream}

0 commit comments

Comments
 (0)
Please sign in to comment.