-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
credentials: create API for transport security level information #3214
Conversation
4ebef55
to
f12549f
Compare
Friendly ping :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make sure travis is green. From the error it seems like gofmt
wasn't run on grpclb_test
. You can run vet.sh
locally before pushing updates. (I'd recommend running via VET_SKIP_PROTO=1 vet.sh
to skip some slower checks that shouldn't affect you.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good. One question:
In clientconn.go, it checks if any PerRPCCredentials require transport security, and fails early.
Do we also want to check SecurityLevel there as well?
credentials/credentials.go
Outdated
// EnableSecurityLevelCheck checks if security level examination should be enabled. It will be enabled | ||
// only if 1) AuthInfo is an instance of ConnAuthInfo and 2) rpcCred implements | ||
// MinimumSecurityLevel interface. | ||
func EnableSecurityLevelCheck(authInfo AuthInfo, rpcCred PerRPCCredentials) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ShouldCheckSecurityLevel maybe a better name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Jiangtao, we decided not to do a centralized check, but let each PerRPCCredentials to implement its own check in GetRequestMetadata().
815bfb3
to
e501cd9
Compare
@dfawley The PR is updated per our off-line discussion. Could you please take a look? |
credentials/credentials.go
Outdated
|
||
// CommonAuthInfo contains authenticated information common to AuthInfo implementations. | ||
type CommonAuthInfo struct { | ||
Level SecurityLevel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: SecurityLevel SecurityLevel
. IMO "Level" by itself is not distinct enough.
@dfawley The comment is addressed. PTAL. Also, the failed tests do not seem to relate to my PR. |
credentials/credentials_test.go
Outdated
return "testAuthInfo" | ||
} | ||
|
||
func TestCheckSecurityLevel(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use table-style tests:
testCases := []struct{
authLevel SecurityLevel
testLevel SecurityLevel
want bool
}{{
authLevel: PrivacyAndIntegrity,
testLevel: PrivacyAndIntegrity,
want: true
}, {
authLevel: IntegrityOnly,
testLevel: PrivacyAndIntegrity,
want: false
}
....
}
for _, tc := range testCases {
// make testAuthInfo, call CheckSecurityLevel, check result
}
This doesn't have to be exhaustive, but should check a few different cases.
credentials/credentials.go
Outdated
} | ||
|
||
// CommonInfo returns the pointer to CommonAuthInfo struct. | ||
func (c *CommonAuthInfo) CommonInfo() *CommonAuthInfo { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My mistake: s/CommonInfo/CommonAuthInfo/g
please. CommonInfo()
doesn't seem sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per our offline discussion, the name is changed to commonAuthInfo()
Thanks Doug for the comments and I am currently working on addressing them. I will let you know once it's ready. |
59d169c
to
3a03528
Compare
All comments are addressed, PTAL. @dfawley |
credentials/credentials.go
Outdated
} | ||
|
||
// CommonAuthInfo returns the pointer to CommonAuthInfo struct. | ||
func (c *CommonAuthInfo) commonAuthInfo() *CommonAuthInfo { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, bad suggestion on my part. I think it will make sense to allow users to access this in an AuthInfo
, if present. GetCommonAuthInfo
should be fine. It seems the accessor-style name is unavoidable here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries. Renaming is done in the next commit.
credentials/credentials.go
Outdated
case PrivacyAndIntegrity: | ||
return "PrivacyAndIntegrity" | ||
} | ||
return "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fmt.Sprintf("invalid SecurityLevel: %v", int(s))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in the next commit.
credentials/credentials.go
Outdated
@@ -50,6 +51,49 @@ type PerRPCCredentials interface { | |||
RequireTransportSecurity() bool | |||
} | |||
|
|||
// SecurityLevel defines the protection level on an established channel. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throughout: please don't use "channel". gRPC-Go does not use that term. You can use "connection" for an individual connection or "ClientConn" for a grpc.ClientConn
connected to potentially many backends.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in the next commit.
All comments are addressed (again :) PTAL. |
FYI: travis is red:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more small things, then I think this should be good to go.
credentials/credentials.go
Outdated
@@ -127,6 +169,8 @@ type Bundle interface { | |||
type RequestInfo struct { | |||
// The method passed to Invoke or NewStream for this RPC. (For proto methods, this has the format "/some.Service/Method") | |||
Method string | |||
// AuthInfo contains the information resulted from a security handshake (TransportCredentials.ClientHandshake, TransportCredentials.ServerHandshake) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/resulted//.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
credentials/oauth/oauth.go
Outdated
@@ -42,6 +42,9 @@ func (ts TokenSource) GetRequestMetadata(ctx context.Context, uri ...string) (ma | |||
if err != nil { | |||
return nil, err | |||
} | |||
if !credentials.CheckSecurityLevel(ctx, credentials.PrivacyAndIntegrity) { | |||
return nil, fmt.Errorf("connection is not secure enough to transfer TokenSource PerRPCCredentials which requires PrivacyAndIntegrity") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmmm.. ideally this would show more information, namely the SecurityLevel
of the connection.
CheckSecurityLevel
could return an error
instead of bool
to facilitate this.
Maybe something like fmt.Errorf("requires SecurityLevel %v; connection has %v", requiredLevel, hasLevel)
? And this can wrap: fmt.Errorf("unable to transfer TokenSource PerRPCCredentials: %v", err)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. CheckSecurityLevel
now returns error
instead of bool
, and more complete error messages are printed in oauth.go
.
credentials/credentials.go
Outdated
} | ||
ri, _ := RequestInfoFromContext(ctx) | ||
if ri.AuthInfo == nil { | ||
return errors.New("RequestInfo does not contain AuthInfo struct") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the only real way to get here is if ctx
does not contain a RequestInfo
(i.e. it was called with the wrong context). I would say "unable to obtain SecurityLevel from context".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
bef9360
to
bf6cafe
Compare
Thanks much @dfawley for detailed reviews! |
@dfawley Do you have any other comments on the PR? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add "experimental" comments on SecurityLevel
and CommonAuthInfo
, otherwise LGTM.
This PR does the following:
ConnAuthInfo
type struct that is a wrapper of credentials.AuthInfo and also contains the security level of an established channel. ExistingTransportCredentials
implementations are modified to returnConnAuthInfo
upon finishing the handshake.credentials.PerRPCCredentials
implementations (JWT, Oauth2).PerRPCCredentials
on a channel. For backward-compatibility we sill preserve the original checking behavior (i.e., usingRequreTransportSecurity()
).