go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/auth/handlers_test.go (about)

     1  // Copyright 2016 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package auth
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"net/http"
    21  	"net/http/httptest"
    22  	"testing"
    23  
    24  	"go.chromium.org/luci/server/auth/signing"
    25  	"go.chromium.org/luci/server/caching"
    26  	"go.chromium.org/luci/server/router"
    27  
    28  	. "github.com/smartystreets/goconvey/convey"
    29  	. "go.chromium.org/luci/common/testing/assertions"
    30  )
    31  
    32  func withSigner(s signing.Signer) router.MiddlewareChain {
    33  	return router.NewMiddlewareChain(
    34  		func(c *router.Context, next router.Handler) {
    35  			c.Request = c.Request.WithContext(ModifyConfig(c.Request.Context(), func(cfg Config) Config {
    36  				cfg.Signer = s
    37  				return cfg
    38  			}))
    39  			next(c)
    40  		},
    41  	)
    42  }
    43  
    44  func TestCertificatesHandler(t *testing.T) {
    45  	t.Parallel()
    46  
    47  	call := func(s signing.Signer) (*signing.PublicCertificates, error) {
    48  		r := router.New()
    49  		InstallHandlers(r, withSigner(s))
    50  		ts := httptest.NewServer(r)
    51  		defer ts.Close()
    52  		// Note: there are two contexts. One for outer /certificates call
    53  		// (this one), and another for /certificates request handler (it is setup
    54  		// in the middleware chain above).
    55  		ctx := caching.WithEmptyProcessCache(context.Background())
    56  		ctx = ModifyConfig(ctx, func(cfg Config) Config {
    57  			cfg.AnonymousTransport = func(context.Context) http.RoundTripper {
    58  				return http.DefaultTransport
    59  			}
    60  			return cfg
    61  		})
    62  		return signing.FetchCertificates(ctx, ts.URL+"/auth/api/v1/server/certificates")
    63  	}
    64  
    65  	Convey("Works", t, func() {
    66  		certs, err := call(&phonySigner{})
    67  		So(err, ShouldBeNil)
    68  		So(len(certs.Certificates), ShouldEqual, 1)
    69  	})
    70  
    71  	Convey("No signer", t, func() {
    72  		_, err := call(nil)
    73  		So(err, ShouldErrLike, "HTTP code (404)")
    74  	})
    75  
    76  	Convey("Error getting certs", t, func() {
    77  		_, err := call(&phonySigner{errors.New("fail")})
    78  		So(err, ShouldErrLike, "HTTP code (500)")
    79  	})
    80  }
    81  
    82  func TestServiceInfoHandler(t *testing.T) {
    83  	t.Parallel()
    84  
    85  	Convey("Works", t, func() {
    86  		r := router.New()
    87  		signer := &phonySigner{}
    88  		InstallHandlers(r, withSigner(signer))
    89  
    90  		w := httptest.NewRecorder()
    91  		req, _ := http.NewRequest("GET", "/auth/api/v1/server/info", nil)
    92  		r.ServeHTTP(w, req)
    93  		So(w.Code, ShouldEqual, 200)
    94  		So(w.Body.String(), ShouldResemble,
    95  			`{"app_id":"phony-app","app_runtime":"go",`+
    96  				`"app_runtime_version":"go1.5.1",`+
    97  				`"app_version":"1234-abcdef","service_account_name":`+
    98  				`"phony-app-account@example.com"}`+"\n")
    99  
   100  		signer.err = errors.New("fail")
   101  
   102  		w = httptest.NewRecorder()
   103  		req, _ = http.NewRequest("GET", "/auth/api/v1/server/info", nil)
   104  		r.ServeHTTP(w, req)
   105  		So(w.Code, ShouldEqual, 500)
   106  		So(w.Body.String(), ShouldResemble, "{\"error\":\"Can't grab service info - fail\"}\n")
   107  	})
   108  }
   109  
   110  func TestClientIDHandler(t *testing.T) {
   111  	t.Parallel()
   112  
   113  	Convey("Works", t, func() {
   114  		var clientIDErr error
   115  		modConfig := router.NewMiddlewareChain(
   116  			func(c *router.Context, next router.Handler) {
   117  				c.Request = c.Request.WithContext(ModifyConfig(c.Request.Context(), func(cfg Config) Config {
   118  					cfg.FrontendClientID = func(context.Context) (string, error) {
   119  						return "fake-client-id", clientIDErr
   120  					}
   121  					return cfg
   122  				}))
   123  				next(c)
   124  			},
   125  		)
   126  
   127  		r := router.New()
   128  		InstallHandlers(r, modConfig)
   129  
   130  		w := httptest.NewRecorder()
   131  		req, _ := http.NewRequest("GET", "/auth/api/v1/server/client_id", nil)
   132  		r.ServeHTTP(w, req)
   133  		So(w.Code, ShouldEqual, 200)
   134  		So(w.Body.String(), ShouldResemble, `{"client_id":"fake-client-id"}`+"\n")
   135  
   136  		clientIDErr = errors.New("fail")
   137  
   138  		w = httptest.NewRecorder()
   139  		req, _ = http.NewRequest("GET", "/auth/api/v1/server/client_id", nil)
   140  		r.ServeHTTP(w, req)
   141  		So(w.Code, ShouldEqual, 500)
   142  		So(w.Body.String(), ShouldResemble, "{\"error\":\"Can't grab the client ID - fail\"}\n")
   143  	})
   144  }
   145  
   146  ///
   147  
   148  type phonySigner struct {
   149  	err error
   150  }
   151  
   152  func (s *phonySigner) SignBytes(ctx context.Context, blob []byte) (string, []byte, error) {
   153  	if s.err != nil {
   154  		return "", nil, s.err
   155  	}
   156  	return "phonyKey", []byte("signature"), nil
   157  }
   158  
   159  func (s *phonySigner) Certificates(ctx context.Context) (*signing.PublicCertificates, error) {
   160  	if s.err != nil {
   161  		return nil, s.err
   162  	}
   163  	return &signing.PublicCertificates{
   164  		Certificates: []signing.Certificate{
   165  			{
   166  				KeyName:            "phonyKey",
   167  				X509CertificatePEM: "phonyPEM",
   168  			},
   169  		},
   170  	}, nil
   171  }
   172  
   173  func (s *phonySigner) ServiceInfo(ctx context.Context) (*signing.ServiceInfo, error) {
   174  	if s.err != nil {
   175  		return nil, s.err
   176  	}
   177  	return &signing.ServiceInfo{
   178  		AppID:              "phony-app",
   179  		AppRuntime:         "go",
   180  		AppRuntimeVersion:  "go1.5.1",
   181  		AppVersion:         "1234-abcdef",
   182  		ServiceAccountName: "phony-app-account@example.com",
   183  	}, nil
   184  }