devices: switch "default" device type to two built-in default device types (#2835)

This commit is contained in:
Caleb Doxsey 2021-12-20 10:44:29 -07:00 committed by GitHub
parent 9408401dbd
commit a3be1b7cc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 22 deletions

View file

@ -16,6 +16,7 @@ import (
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/urlutil"
"github.com/pomerium/pomerium/pkg/cryptutil"
"github.com/pomerium/pomerium/pkg/webauthnutil"
)
// ValidateOptions checks that configuration are complete and valid.
@ -133,7 +134,7 @@ func (a *Authenticate) getWebAuthnURL(values url.Values) (*url.URL, error) {
uri = uri.ResolveReference(&url.URL{
Path: "/.pomerium/webauthn",
RawQuery: buildURLValues(values, url.Values{
urlutil.QueryDeviceType: {"default"},
urlutil.QueryDeviceType: {webauthnutil.DefaultDeviceType},
urlutil.QueryEnrollmentToken: nil,
urlutil.QueryRedirectURI: {uri.ResolveReference(&url.URL{
Path: "/.pomerium/",

View file

@ -24,6 +24,7 @@ import (
"github.com/pomerium/pomerium/internal/telemetry/requestid"
"github.com/pomerium/pomerium/internal/urlutil"
"github.com/pomerium/pomerium/pkg/policy/criteria"
"github.com/pomerium/pomerium/pkg/webauthnutil"
)
func (a *Authorize) handleResultAllowed(
@ -212,7 +213,7 @@ func (a *Authorize) requireWebAuthnResponse(
if deviceType, ok := result.Allow.AdditionalData["device_type"].(string); ok {
q.Set(urlutil.QueryDeviceType, deviceType)
} else {
q.Set(urlutil.QueryDeviceType, "default")
q.Set(urlutil.QueryDeviceType, webauthnutil.DefaultDeviceType)
}
q.Set(urlutil.QueryRedirectURI, checkRequestURL.String())
signinURL.RawQuery = q.Encode()

View file

@ -6,15 +6,25 @@ import (
"github.com/pomerium/webauthn/cose"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"github.com/pomerium/pomerium/pkg/grpc/databroker"
"github.com/pomerium/pomerium/pkg/grpc/device"
)
// DefaultDeviceType is the default device type when none is specified.
const DefaultDeviceType = "any"
var supportedPublicKeyCredentialParameters = []*device.WebAuthnOptions_PublicKeyCredentialParameters{
{Type: device.WebAuthnOptions_PUBLIC_KEY, Alg: int64(cose.AlgorithmES256)},
{Type: device.WebAuthnOptions_PUBLIC_KEY, Alg: int64(cose.AlgorithmRS256)},
{Type: device.WebAuthnOptions_PUBLIC_KEY, Alg: int64(cose.AlgorithmRS1)},
}
var predefinedDeviceTypes = map[string]*device.Type{
"default": {
Id: "default",
Name: "default",
"any": {
Id: "any",
Name: "Any",
Specifier: &device.Type_Webauthn{
Webauthn: &device.Type_WebAuthn{
Options: &device.WebAuthnOptions{
@ -22,11 +32,24 @@ var predefinedDeviceTypes = map[string]*device.Type{
AuthenticatorSelection: &device.WebAuthnOptions_AuthenticatorSelectionCriteria{
UserVerification: device.WebAuthnOptions_USER_VERIFICATION_PREFERRED.Enum(),
},
PubKeyCredParams: []*device.WebAuthnOptions_PublicKeyCredentialParameters{
{Type: device.WebAuthnOptions_PUBLIC_KEY, Alg: int64(cose.AlgorithmES256)},
{Type: device.WebAuthnOptions_PUBLIC_KEY, Alg: int64(cose.AlgorithmRS256)},
{Type: device.WebAuthnOptions_PUBLIC_KEY, Alg: int64(cose.AlgorithmRS1)},
PubKeyCredParams: supportedPublicKeyCredentialParameters,
},
},
},
},
"enclave_only": {
Id: "enclave_only",
Name: "Secure Enclave Only",
Specifier: &device.Type_Webauthn{
Webauthn: &device.Type_WebAuthn{
Options: &device.WebAuthnOptions{
Attestation: device.WebAuthnOptions_DIRECT.Enum(),
AuthenticatorSelection: &device.WebAuthnOptions_AuthenticatorSelectionCriteria{
UserVerification: device.WebAuthnOptions_USER_VERIFICATION_PREFERRED.Enum(),
RequireResidentKey: proto.Bool(true),
AuthenticatorAttachment: device.WebAuthnOptions_PLATFORM.Enum(),
},
PubKeyCredParams: supportedPublicKeyCredentialParameters,
},
},
},

View file

@ -21,9 +21,9 @@ func TestGetDeviceType(t *testing.T) {
client := &mockDataBrokerServiceClient{
get: func(ctx context.Context, in *databroker.GetRequest, opts ...grpc.CallOption) (*databroker.GetResponse, error) {
assert.Equal(t, "type.googleapis.com/pomerium.device.Type", in.GetType())
assert.Equal(t, "default", in.GetId())
assert.Equal(t, "any", in.GetId())
any, _ := anypb.New(&device.Type{
Id: "default",
Id: "any",
Name: "Example",
})
return &databroker.GetResponse{
@ -35,7 +35,7 @@ func TestGetDeviceType(t *testing.T) {
}, nil
},
}
deviceType, err := GetDeviceType(ctx, client, "default")
deviceType, err := GetDeviceType(ctx, client, "any")
assert.NoError(t, err)
assert.Equal(t, "Example", deviceType.GetName())
})
@ -45,9 +45,9 @@ func TestGetDeviceType(t *testing.T) {
return nil, status.Error(codes.NotFound, "not found")
},
}
deviceType, err := GetDeviceType(ctx, client, "default")
deviceType, err := GetDeviceType(ctx, client, "any")
assert.NoError(t, err)
assert.Equal(t, "default", deviceType.GetName())
assert.Equal(t, "Any", deviceType.GetName())
})
t.Run("not found", func(t *testing.T) {
client := &mockDataBrokerServiceClient{

View file

@ -14,21 +14,21 @@ import (
func TestGenerateCreationOptions(t *testing.T) {
t.Run("random challenge", func(t *testing.T) {
key := []byte{1, 2, 3}
options1 := GenerateCreationOptions(key, predefinedDeviceTypes["default"], &user.User{
options1 := GenerateCreationOptions(key, predefinedDeviceTypes[DefaultDeviceType], &user.User{
Id: "example",
Email: "test@example.com",
Name: "Test User",
})
options2 := GenerateCreationOptions(key, predefinedDeviceTypes["default"], &user.User{
options2 := GenerateCreationOptions(key, predefinedDeviceTypes[DefaultDeviceType], &user.User{
Id: "example",
Email: "test@example.com",
Name: "Test User",
})
assert.NotEqual(t, options1.Challenge, options2.Challenge)
})
t.Run("default", func(t *testing.T) {
t.Run(DefaultDeviceType, func(t *testing.T) {
key := []byte{1, 2, 3}
options := GenerateCreationOptions(key, predefinedDeviceTypes["default"], &user.User{
options := GenerateCreationOptions(key, predefinedDeviceTypes[DefaultDeviceType], &user.User{
Id: "example",
Email: "test@example.com",
Name: "Test User",
@ -65,13 +65,13 @@ func TestGenerateCreationOptions(t *testing.T) {
func TestGenerateRequestOptions(t *testing.T) {
t.Run("random challenge", func(t *testing.T) {
key := []byte{1, 2, 3}
options1 := GenerateRequestOptions(key, predefinedDeviceTypes["default"], nil)
options2 := GenerateRequestOptions(key, predefinedDeviceTypes["default"], nil)
options1 := GenerateRequestOptions(key, predefinedDeviceTypes[DefaultDeviceType], nil)
options2 := GenerateRequestOptions(key, predefinedDeviceTypes[DefaultDeviceType], nil)
assert.NotEqual(t, options1.Challenge, options2.Challenge)
})
t.Run("default", func(t *testing.T) {
t.Run(DefaultDeviceType, func(t *testing.T) {
key := []byte{1, 2, 3}
options := GenerateRequestOptions(key, predefinedDeviceTypes["default"], []*device.Credential{
options := GenerateRequestOptions(key, predefinedDeviceTypes[DefaultDeviceType], []*device.Credential{
{Id: "device1", Specifier: &device.Credential_Webauthn{Webauthn: &device.Credential_WebAuthn{
Id: []byte{4, 5, 6},
}}},