123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- // Copyright 2017 The etcd Authors
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package auth
- import (
- "context"
- "fmt"
- "testing"
- "go.uber.org/zap"
- )
- const (
- jwtRSAPubKey = "../integration/fixtures/server.crt"
- jwtRSAPrivKey = "../integration/fixtures/server.key.insecure"
- jwtECPubKey = "../integration/fixtures/server-ecdsa.crt"
- jwtECPrivKey = "../integration/fixtures/server-ecdsa.key.insecure"
- )
- func TestJWTInfo(t *testing.T) {
- optsMap := map[string]map[string]string{
- "RSA-priv": {
- "priv-key": jwtRSAPrivKey,
- "sign-method": "RS256",
- "ttl": "1h",
- },
- "RSA": {
- "pub-key": jwtRSAPubKey,
- "priv-key": jwtRSAPrivKey,
- "sign-method": "RS256",
- },
- "RSAPSS-priv": {
- "priv-key": jwtRSAPrivKey,
- "sign-method": "PS256",
- },
- "RSAPSS": {
- "pub-key": jwtRSAPubKey,
- "priv-key": jwtRSAPrivKey,
- "sign-method": "PS256",
- },
- "ECDSA-priv": {
- "priv-key": jwtECPrivKey,
- "sign-method": "ES256",
- },
- "ECDSA": {
- "pub-key": jwtECPubKey,
- "priv-key": jwtECPrivKey,
- "sign-method": "ES256",
- },
- "HMAC": {
- "priv-key": jwtECPrivKey, // any file, raw bytes used as shared secret
- "sign-method": "HS256",
- },
- }
- for k, opts := range optsMap {
- t.Run(k, func(tt *testing.T) {
- testJWTInfo(tt, opts)
- })
- }
- }
- func testJWTInfo(t *testing.T, opts map[string]string) {
- lg := zap.NewNop()
- jwt, err := newTokenProviderJWT(lg, opts)
- if err != nil {
- t.Fatal(err)
- }
- ctx := context.TODO()
- token, aerr := jwt.assign(ctx, "abc", 123)
- if aerr != nil {
- t.Fatalf("%#v", aerr)
- }
- ai, ok := jwt.info(ctx, token, 123)
- if !ok {
- t.Fatalf("failed to authenticate with token %s", token)
- }
- if ai.Revision != 123 {
- t.Fatalf("expected revision 123, got %d", ai.Revision)
- }
- ai, ok = jwt.info(ctx, "aaa", 120)
- if ok || ai != nil {
- t.Fatalf("expected aaa to fail to authenticate, got %+v", ai)
- }
- // test verify-only provider
- if opts["pub-key"] != "" && opts["priv-key"] != "" {
- t.Run("verify-only", func(t *testing.T) {
- newOpts := make(map[string]string, len(opts))
- for k, v := range opts {
- newOpts[k] = v
- }
- delete(newOpts, "priv-key")
- verify, err := newTokenProviderJWT(lg, newOpts)
- if err != nil {
- t.Fatal(err)
- }
- ai, ok := verify.info(ctx, token, 123)
- if !ok {
- t.Fatalf("failed to authenticate with token %s", token)
- }
- if ai.Revision != 123 {
- t.Fatalf("expected revision 123, got %d", ai.Revision)
- }
- ai, ok = verify.info(ctx, "aaa", 120)
- if ok || ai != nil {
- t.Fatalf("expected aaa to fail to authenticate, got %+v", ai)
- }
- _, aerr := verify.assign(ctx, "abc", 123)
- if aerr != ErrVerifyOnly {
- t.Fatalf("unexpected error when attempting to sign with public key: %v", aerr)
- }
- })
- }
- }
- func TestJWTBad(t *testing.T) {
- var badCases = map[string]map[string]string{
- "no options": {},
- "invalid method": {
- "sign-method": "invalid",
- },
- "rsa no key": {
- "sign-method": "RS256",
- },
- "invalid ttl": {
- "sign-method": "RS256",
- "ttl": "forever",
- },
- "rsa invalid public key": {
- "sign-method": "RS256",
- "pub-key": jwtRSAPrivKey,
- "priv-key": jwtRSAPrivKey,
- },
- "rsa invalid private key": {
- "sign-method": "RS256",
- "pub-key": jwtRSAPubKey,
- "priv-key": jwtRSAPubKey,
- },
- "hmac no key": {
- "sign-method": "HS256",
- },
- "hmac pub key": {
- "sign-method": "HS256",
- "pub-key": jwtRSAPubKey,
- },
- "missing public key file": {
- "sign-method": "HS256",
- "pub-key": "missing-file",
- },
- "missing private key file": {
- "sign-method": "HS256",
- "priv-key": "missing-file",
- },
- "ecdsa no key": {
- "sign-method": "ES256",
- },
- "ecdsa invalid public key": {
- "sign-method": "ES256",
- "pub-key": jwtECPrivKey,
- "priv-key": jwtECPrivKey,
- },
- "ecdsa invalid private key": {
- "sign-method": "ES256",
- "pub-key": jwtECPubKey,
- "priv-key": jwtECPubKey,
- },
- }
- lg := zap.NewNop()
- for k, v := range badCases {
- t.Run(k, func(t *testing.T) {
- _, err := newTokenProviderJWT(lg, v)
- if err == nil {
- t.Errorf("expected error for options %v", v)
- }
- })
- }
- }
- // testJWTOpts is useful for passing to NewTokenProvider which requires a string.
- func testJWTOpts() string {
- return fmt.Sprintf("%s,pub-key=%s,priv-key=%s,sign-method=RS256", tokenTypeJWT, jwtRSAPubKey, jwtRSAPrivKey)
- }
|