auth_test.go 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package auth
  14. // This file tests authentication and (soon) authorization of HTTP requests to a master object.
  15. // It does not use the client in pkg/client/... because authentication and authorization needs
  16. // to work for any client of the HTTP interface.
  17. import (
  18. "bytes"
  19. "context"
  20. "encoding/json"
  21. "fmt"
  22. "io/ioutil"
  23. "net/http"
  24. "net/http/httptest"
  25. "net/url"
  26. "os"
  27. "strconv"
  28. "strings"
  29. "testing"
  30. "time"
  31. authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
  32. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  33. "k8s.io/apiserver/pkg/authentication/authenticator"
  34. "k8s.io/apiserver/pkg/authentication/group"
  35. "k8s.io/apiserver/pkg/authentication/request/bearertoken"
  36. "k8s.io/apiserver/pkg/authentication/serviceaccount"
  37. "k8s.io/apiserver/pkg/authentication/token/cache"
  38. "k8s.io/apiserver/pkg/authentication/user"
  39. "k8s.io/apiserver/pkg/authorization/authorizer"
  40. "k8s.io/apiserver/pkg/authorization/authorizerfactory"
  41. "k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest"
  42. "k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
  43. v1 "k8s.io/client-go/tools/clientcmd/api/v1"
  44. "k8s.io/kubernetes/pkg/apis/autoscaling"
  45. api "k8s.io/kubernetes/pkg/apis/core"
  46. "k8s.io/kubernetes/pkg/apis/extensions"
  47. "k8s.io/kubernetes/pkg/auth/authorizer/abac"
  48. "k8s.io/kubernetes/test/integration"
  49. "k8s.io/kubernetes/test/integration/framework"
  50. )
  51. const (
  52. AliceToken string = "abc123" // username: alice. Present in token file.
  53. BobToken string = "xyz987" // username: bob. Present in token file.
  54. UnknownToken string = "qwerty" // Not present in token file.
  55. )
  56. func getTestTokenAuth() authenticator.Request {
  57. tokenAuthenticator := tokentest.New()
  58. tokenAuthenticator.Tokens[AliceToken] = &user.DefaultInfo{Name: "alice", UID: "1"}
  59. tokenAuthenticator.Tokens[BobToken] = &user.DefaultInfo{Name: "bob", UID: "2"}
  60. return group.NewGroupAdder(bearertoken.New(tokenAuthenticator), []string{user.AllAuthenticated})
  61. }
  62. func getTestWebhookTokenAuth(serverURL string) (authenticator.Request, error) {
  63. kubecfgFile, err := ioutil.TempFile("", "webhook-kubecfg")
  64. if err != nil {
  65. return nil, err
  66. }
  67. defer os.Remove(kubecfgFile.Name())
  68. config := v1.Config{
  69. Clusters: []v1.NamedCluster{
  70. {
  71. Cluster: v1.Cluster{Server: serverURL},
  72. },
  73. },
  74. }
  75. if err := json.NewEncoder(kubecfgFile).Encode(config); err != nil {
  76. return nil, err
  77. }
  78. webhookTokenAuth, err := webhook.New(kubecfgFile.Name(), "v1beta1", nil)
  79. if err != nil {
  80. return nil, err
  81. }
  82. return bearertoken.New(cache.New(webhookTokenAuth, false, 2*time.Minute, 2*time.Minute)), nil
  83. }
  84. func path(resource, namespace, name string) string {
  85. return pathWithPrefix("", resource, namespace, name)
  86. }
  87. func pathWithPrefix(prefix, resource, namespace, name string) string {
  88. path := "/api/v1"
  89. if prefix != "" {
  90. path = path + "/" + prefix
  91. }
  92. if namespace != "" {
  93. path = path + "/namespaces/" + namespace
  94. }
  95. // Resource names are lower case.
  96. resource = strings.ToLower(resource)
  97. if resource != "" {
  98. path = path + "/" + resource
  99. }
  100. if name != "" {
  101. path = path + "/" + name
  102. }
  103. return path
  104. }
  105. func pathWithSubResource(resource, namespace, name, subresource string) string {
  106. path := pathWithPrefix("", resource, namespace, name)
  107. if subresource != "" {
  108. path = path + "/" + subresource
  109. }
  110. return path
  111. }
  112. func timeoutPath(resource, namespace, name string) string {
  113. return addTimeoutFlag(path(resource, namespace, name))
  114. }
  115. // Bodies for requests used in subsequent tests.
  116. var aPod = `
  117. {
  118. "kind": "Pod",
  119. "apiVersion": "v1",
  120. "metadata": {
  121. "name": "a",
  122. "creationTimestamp": null%s
  123. },
  124. "spec": {
  125. "containers": [
  126. {
  127. "name": "foo",
  128. "image": "bar/foo"
  129. }
  130. ]
  131. }
  132. }
  133. `
  134. var aRC = `
  135. {
  136. "kind": "ReplicationController",
  137. "apiVersion": "v1",
  138. "metadata": {
  139. "name": "a",
  140. "labels": {
  141. "name": "a"
  142. }%s
  143. },
  144. "spec": {
  145. "replicas": 2,
  146. "selector": {
  147. "name": "a"
  148. },
  149. "template": {
  150. "metadata": {
  151. "labels": {
  152. "name": "a"
  153. }
  154. },
  155. "spec": {
  156. "containers": [
  157. {
  158. "name": "foo",
  159. "image": "bar/foo"
  160. }
  161. ]
  162. }
  163. }
  164. }
  165. }
  166. `
  167. var aService = `
  168. {
  169. "kind": "Service",
  170. "apiVersion": "v1",
  171. "metadata": {
  172. "name": "a",
  173. "labels": {
  174. "name": "a"
  175. }%s
  176. },
  177. "spec": {
  178. "ports": [
  179. {
  180. "protocol": "TCP",
  181. "port": 8000
  182. }
  183. ],
  184. "selector": {
  185. "name": "a"
  186. },
  187. "clusterIP": "10.0.0.100"
  188. }
  189. }
  190. `
  191. var aNode = `
  192. {
  193. "kind": "Node",
  194. "apiVersion": "v1",
  195. "metadata": {
  196. "name": "a"%s
  197. },
  198. "spec": {
  199. "externalID": "external"
  200. }
  201. }
  202. `
  203. func aEvent(namespace string) string {
  204. return `
  205. {
  206. "kind": "Event",
  207. "apiVersion": "v1",
  208. "metadata": {
  209. "name": "a"%s
  210. },
  211. "involvedObject": {
  212. "kind": "Pod",
  213. "namespace": "` + namespace + `",
  214. "name": "a",
  215. "apiVersion": "v1"
  216. }
  217. }
  218. `
  219. }
  220. var aBinding = `
  221. {
  222. "kind": "Binding",
  223. "apiVersion": "v1",
  224. "metadata": {
  225. "name": "a"%s
  226. },
  227. "target": {
  228. "name": "10.10.10.10"
  229. }
  230. }
  231. `
  232. var emptyEndpoints = `
  233. {
  234. "kind": "Endpoints",
  235. "apiVersion": "v1",
  236. "metadata": {
  237. "name": "a"%s
  238. }
  239. }
  240. `
  241. var aEndpoints = `
  242. {
  243. "kind": "Endpoints",
  244. "apiVersion": "v1",
  245. "metadata": {
  246. "name": "a"%s
  247. },
  248. "subsets": [
  249. {
  250. "addresses": [
  251. {
  252. "ip": "10.10.1.1"
  253. }
  254. ],
  255. "ports": [
  256. {
  257. "port": 1909,
  258. "protocol": "TCP"
  259. }
  260. ]
  261. }
  262. ]
  263. }
  264. `
  265. var deleteNow = `
  266. {
  267. "kind": "DeleteOptions",
  268. "apiVersion": "v1",
  269. "gracePeriodSeconds": 0%s
  270. }
  271. `
  272. // To ensure that a POST completes before a dependent GET, set a timeout.
  273. func addTimeoutFlag(URLString string) string {
  274. u, _ := url.Parse(URLString)
  275. values := u.Query()
  276. values.Set("timeout", "60s")
  277. u.RawQuery = values.Encode()
  278. return u.String()
  279. }
  280. func getTestRequests(namespace string) []struct {
  281. verb string
  282. URL string
  283. body string
  284. statusCodes map[int]bool // allowed status codes.
  285. } {
  286. requests := []struct {
  287. verb string
  288. URL string
  289. body string
  290. statusCodes map[int]bool // Set of expected resp.StatusCode if all goes well.
  291. }{
  292. // Normal methods on pods
  293. {"GET", path("pods", "", ""), "", integration.Code200},
  294. {"GET", path("pods", namespace, ""), "", integration.Code200},
  295. {"POST", timeoutPath("pods", namespace, ""), aPod, integration.Code201},
  296. {"PUT", timeoutPath("pods", namespace, "a"), aPod, integration.Code200},
  297. {"GET", path("pods", namespace, "a"), "", integration.Code200},
  298. // GET and POST for /exec should return Bad Request (400) since the pod has not been assigned a node yet.
  299. {"GET", path("pods", namespace, "a") + "/exec", "", integration.Code400},
  300. {"POST", path("pods", namespace, "a") + "/exec", "", integration.Code400},
  301. // PUT for /exec should return Method Not Allowed (405).
  302. {"PUT", path("pods", namespace, "a") + "/exec", "", integration.Code405},
  303. // GET and POST for /portforward should return Bad Request (400) since the pod has not been assigned a node yet.
  304. {"GET", path("pods", namespace, "a") + "/portforward", "", integration.Code400},
  305. {"POST", path("pods", namespace, "a") + "/portforward", "", integration.Code400},
  306. // PUT for /portforward should return Method Not Allowed (405).
  307. {"PUT", path("pods", namespace, "a") + "/portforward", "", integration.Code405},
  308. {"PATCH", path("pods", namespace, "a"), "{%v}", integration.Code200},
  309. {"DELETE", timeoutPath("pods", namespace, "a"), deleteNow, integration.Code200},
  310. // Non-standard methods (not expected to work,
  311. // but expected to pass/fail authorization prior to
  312. // failing validation.
  313. {"OPTIONS", path("pods", namespace, ""), "", integration.Code405},
  314. {"OPTIONS", path("pods", namespace, "a"), "", integration.Code405},
  315. {"HEAD", path("pods", namespace, ""), "", integration.Code405},
  316. {"HEAD", path("pods", namespace, "a"), "", integration.Code405},
  317. {"TRACE", path("pods", namespace, ""), "", integration.Code405},
  318. {"TRACE", path("pods", namespace, "a"), "", integration.Code405},
  319. {"NOSUCHVERB", path("pods", namespace, ""), "", integration.Code405},
  320. // Normal methods on services
  321. {"GET", path("services", "", ""), "", integration.Code200},
  322. {"GET", path("services", namespace, ""), "", integration.Code200},
  323. {"POST", timeoutPath("services", namespace, ""), aService, integration.Code201},
  324. // Create an endpoint for the service (this is done automatically by endpoint controller
  325. // whenever a service is created, but this test does not run that controller)
  326. {"POST", timeoutPath("endpoints", namespace, ""), emptyEndpoints, integration.Code201},
  327. // Should return service unavailable when endpoint.subset is empty.
  328. {"GET", pathWithSubResource("services", namespace, "a", "proxy") + "/", "", integration.Code503},
  329. {"PUT", timeoutPath("services", namespace, "a"), aService, integration.Code200},
  330. {"GET", path("services", namespace, "a"), "", integration.Code200},
  331. {"DELETE", timeoutPath("endpoints", namespace, "a"), "", integration.Code200},
  332. {"DELETE", timeoutPath("services", namespace, "a"), "", integration.Code200},
  333. // Normal methods on replicationControllers
  334. {"GET", path("replicationControllers", "", ""), "", integration.Code200},
  335. {"GET", path("replicationControllers", namespace, ""), "", integration.Code200},
  336. {"POST", timeoutPath("replicationControllers", namespace, ""), aRC, integration.Code201},
  337. {"PUT", timeoutPath("replicationControllers", namespace, "a"), aRC, integration.Code200},
  338. {"GET", path("replicationControllers", namespace, "a"), "", integration.Code200},
  339. {"DELETE", timeoutPath("replicationControllers", namespace, "a"), "", integration.Code200},
  340. // Normal methods on endpoints
  341. {"GET", path("endpoints", "", ""), "", integration.Code200},
  342. {"GET", path("endpoints", namespace, ""), "", integration.Code200},
  343. {"POST", timeoutPath("endpoints", namespace, ""), aEndpoints, integration.Code201},
  344. {"PUT", timeoutPath("endpoints", namespace, "a"), aEndpoints, integration.Code200},
  345. {"GET", path("endpoints", namespace, "a"), "", integration.Code200},
  346. {"DELETE", timeoutPath("endpoints", namespace, "a"), "", integration.Code200},
  347. // Normal methods on nodes
  348. {"GET", path("nodes", "", ""), "", integration.Code200},
  349. {"POST", timeoutPath("nodes", "", ""), aNode, integration.Code201},
  350. {"PUT", timeoutPath("nodes", "", "a"), aNode, integration.Code200},
  351. {"GET", path("nodes", "", "a"), "", integration.Code200},
  352. {"DELETE", timeoutPath("nodes", "", "a"), "", integration.Code200},
  353. // Normal methods on events
  354. {"GET", path("events", "", ""), "", integration.Code200},
  355. {"GET", path("events", namespace, ""), "", integration.Code200},
  356. {"POST", timeoutPath("events", namespace, ""), aEvent(namespace), integration.Code201},
  357. {"PUT", timeoutPath("events", namespace, "a"), aEvent(namespace), integration.Code200},
  358. {"GET", path("events", namespace, "a"), "", integration.Code200},
  359. {"DELETE", timeoutPath("events", namespace, "a"), "", integration.Code200},
  360. // Normal methods on bindings
  361. {"GET", path("bindings", namespace, ""), "", integration.Code405},
  362. {"POST", timeoutPath("pods", namespace, ""), aPod, integration.Code201}, // Need a pod to bind or you get a 404
  363. {"POST", timeoutPath("bindings", namespace, ""), aBinding, integration.Code201},
  364. {"PUT", timeoutPath("bindings", namespace, "a"), aBinding, integration.Code404},
  365. {"GET", path("bindings", namespace, "a"), "", integration.Code404}, // No bindings instances
  366. {"DELETE", timeoutPath("bindings", namespace, "a"), "", integration.Code404},
  367. // Non-existent object type.
  368. {"GET", path("foo", "", ""), "", integration.Code404},
  369. {"POST", path("foo", namespace, ""), `{"foo": "foo"}`, integration.Code404},
  370. {"PUT", path("foo", namespace, "a"), `{"foo": "foo"}`, integration.Code404},
  371. {"GET", path("foo", namespace, "a"), "", integration.Code404},
  372. {"DELETE", timeoutPath("foo", namespace, ""), "", integration.Code404},
  373. // Special verbs on nodes
  374. {"GET", pathWithSubResource("nodes", namespace, "a", "proxy"), "", integration.Code404},
  375. {"GET", pathWithPrefix("redirect", "nodes", namespace, "a"), "", integration.Code404},
  376. // TODO: test .../watch/..., which doesn't end before the test timeout.
  377. // TODO: figure out how to create a node so that it can successfully proxy/redirect.
  378. // Non-object endpoints
  379. {"GET", "/", "", integration.Code200},
  380. {"GET", "/api", "", integration.Code200},
  381. {"GET", "/healthz", "", integration.Code200},
  382. {"GET", "/version", "", integration.Code200},
  383. {"GET", "/invalidURL", "", integration.Code404},
  384. }
  385. return requests
  386. }
  387. // The TestAuthMode* tests a large number of URLs and checks that they
  388. // are FORBIDDEN or not, depending on the mode. They do not attempt to do
  389. // detailed verification of behaviour beyond authorization. They are not
  390. // fuzz tests.
  391. //
  392. // TODO(etune): write a fuzz test of the REST API.
  393. func TestAuthModeAlwaysAllow(t *testing.T) {
  394. // Set up a master
  395. masterConfig := framework.NewIntegrationTestMasterConfig()
  396. _, s, closeFn := framework.RunAMaster(masterConfig)
  397. defer closeFn()
  398. ns := framework.CreateTestingNamespace("auth-always-allow", s, t)
  399. defer framework.DeleteTestingNamespace(ns, s, t)
  400. transport := http.DefaultTransport
  401. previousResourceVersion := make(map[string]float64)
  402. for _, r := range getTestRequests(ns.Name) {
  403. var bodyStr string
  404. if r.body != "" {
  405. sub := ""
  406. if r.verb == "PUT" {
  407. // For update operations, insert previous resource version
  408. if resVersion := previousResourceVersion[getPreviousResourceVersionKey(r.URL, "")]; resVersion != 0 {
  409. sub += fmt.Sprintf(",\r\n\"resourceVersion\": \"%v\"", resVersion)
  410. }
  411. sub += fmt.Sprintf(",\r\n\"namespace\": %q", ns.Name)
  412. }
  413. bodyStr = fmt.Sprintf(r.body, sub)
  414. }
  415. r.body = bodyStr
  416. bodyBytes := bytes.NewReader([]byte(bodyStr))
  417. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  418. if err != nil {
  419. t.Logf("case %v", r)
  420. t.Fatalf("unexpected error: %v", err)
  421. }
  422. if r.verb == "PATCH" {
  423. req.Header.Set("Content-Type", "application/merge-patch+json")
  424. }
  425. func() {
  426. resp, err := transport.RoundTrip(req)
  427. if err != nil {
  428. t.Logf("case %v", r)
  429. t.Fatalf("unexpected error: %v", err)
  430. }
  431. defer resp.Body.Close()
  432. b, _ := ioutil.ReadAll(resp.Body)
  433. if _, ok := r.statusCodes[resp.StatusCode]; !ok {
  434. t.Logf("case %v", r)
  435. t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode)
  436. t.Errorf("Body: %v", string(b))
  437. } else {
  438. if r.verb == "POST" {
  439. // For successful create operations, extract resourceVersion
  440. id, currentResourceVersion, err := parseResourceVersion(b)
  441. if err == nil {
  442. key := getPreviousResourceVersionKey(r.URL, id)
  443. previousResourceVersion[key] = currentResourceVersion
  444. } else {
  445. t.Logf("error in trying to extract resource version: %s", err)
  446. }
  447. }
  448. }
  449. }()
  450. }
  451. }
  452. func parseResourceVersion(response []byte) (string, float64, error) {
  453. var resultBodyMap map[string]interface{}
  454. err := json.Unmarshal(response, &resultBodyMap)
  455. if err != nil {
  456. return "", 0, fmt.Errorf("unexpected error unmarshaling resultBody: %v", err)
  457. }
  458. metadata, ok := resultBodyMap["metadata"].(map[string]interface{})
  459. if !ok {
  460. return "", 0, fmt.Errorf("unexpected error, metadata not found in JSON response: %v", string(response))
  461. }
  462. id, ok := metadata["name"].(string)
  463. if !ok {
  464. return "", 0, fmt.Errorf("unexpected error, id not found in JSON response: %v", string(response))
  465. }
  466. resourceVersionString, ok := metadata["resourceVersion"].(string)
  467. if !ok {
  468. return "", 0, fmt.Errorf("unexpected error, resourceVersion not found in JSON response: %v", string(response))
  469. }
  470. resourceVersion, err := strconv.ParseFloat(resourceVersionString, 64)
  471. if err != nil {
  472. return "", 0, fmt.Errorf("unexpected error, could not parse resourceVersion as float64, err: %s. JSON response: %v", err, string(response))
  473. }
  474. return id, resourceVersion, nil
  475. }
  476. func getPreviousResourceVersionKey(url, id string) string {
  477. baseURL := strings.Split(url, "?")[0]
  478. key := baseURL
  479. if id != "" {
  480. key = fmt.Sprintf("%s/%v", baseURL, id)
  481. }
  482. return key
  483. }
  484. func TestAuthModeAlwaysDeny(t *testing.T) {
  485. // Set up a master
  486. masterConfig := framework.NewIntegrationTestMasterConfig()
  487. masterConfig.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysDenyAuthorizer()
  488. _, s, closeFn := framework.RunAMaster(masterConfig)
  489. defer closeFn()
  490. ns := framework.CreateTestingNamespace("auth-always-deny", s, t)
  491. defer framework.DeleteTestingNamespace(ns, s, t)
  492. transport := http.DefaultTransport
  493. for _, r := range getTestRequests(ns.Name) {
  494. bodyBytes := bytes.NewReader([]byte(r.body))
  495. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  496. if err != nil {
  497. t.Logf("case %v", r)
  498. t.Fatalf("unexpected error: %v", err)
  499. }
  500. func() {
  501. resp, err := transport.RoundTrip(req)
  502. if err != nil {
  503. t.Logf("case %v", r)
  504. t.Fatalf("unexpected error: %v", err)
  505. }
  506. defer resp.Body.Close()
  507. if resp.StatusCode != http.StatusForbidden {
  508. t.Logf("case %v", r)
  509. t.Errorf("Expected status Forbidden but got status %v", resp.Status)
  510. }
  511. }()
  512. }
  513. }
  514. // Inject into master an authorizer that uses user info.
  515. // TODO(etune): remove this test once a more comprehensive built-in authorizer is implemented.
  516. type allowAliceAuthorizer struct{}
  517. func (allowAliceAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
  518. if a.GetUser() != nil && a.GetUser().GetName() == "alice" {
  519. return authorizer.DecisionAllow, "", nil
  520. }
  521. return authorizer.DecisionNoOpinion, "I can't allow that. Go ask alice.", nil
  522. }
  523. // TestAliceNotForbiddenOrUnauthorized tests a user who is known to
  524. // the authentication system and authorized to do any actions.
  525. func TestAliceNotForbiddenOrUnauthorized(t *testing.T) {
  526. // This file has alice and bob in it.
  527. // Set up a master
  528. masterConfig := framework.NewIntegrationTestMasterConfig()
  529. masterConfig.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
  530. masterConfig.GenericConfig.Authorization.Authorizer = allowAliceAuthorizer{}
  531. _, s, closeFn := framework.RunAMaster(masterConfig)
  532. defer closeFn()
  533. ns := framework.CreateTestingNamespace("auth-alice-not-forbidden", s, t)
  534. defer framework.DeleteTestingNamespace(ns, s, t)
  535. previousResourceVersion := make(map[string]float64)
  536. transport := http.DefaultTransport
  537. for _, r := range getTestRequests(ns.Name) {
  538. token := AliceToken
  539. var bodyStr string
  540. if r.body != "" {
  541. sub := ""
  542. if r.verb == "PUT" {
  543. // For update operations, insert previous resource version
  544. if resVersion := previousResourceVersion[getPreviousResourceVersionKey(r.URL, "")]; resVersion != 0 {
  545. sub += fmt.Sprintf(",\r\n\"resourceVersion\": \"%v\"", resVersion)
  546. }
  547. sub += fmt.Sprintf(",\r\n\"namespace\": %q", ns.Name)
  548. }
  549. bodyStr = fmt.Sprintf(r.body, sub)
  550. }
  551. r.body = bodyStr
  552. bodyBytes := bytes.NewReader([]byte(bodyStr))
  553. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  554. if err != nil {
  555. t.Fatalf("unexpected error: %v", err)
  556. }
  557. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  558. if r.verb == "PATCH" {
  559. req.Header.Set("Content-Type", "application/merge-patch+json")
  560. }
  561. func() {
  562. resp, err := transport.RoundTrip(req)
  563. if err != nil {
  564. t.Logf("case %v", r)
  565. t.Fatalf("unexpected error: %v", err)
  566. }
  567. defer resp.Body.Close()
  568. b, _ := ioutil.ReadAll(resp.Body)
  569. if _, ok := r.statusCodes[resp.StatusCode]; !ok {
  570. t.Logf("case %v", r)
  571. t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode)
  572. t.Errorf("Body: %v", string(b))
  573. } else {
  574. if r.verb == "POST" {
  575. // For successful create operations, extract resourceVersion
  576. id, currentResourceVersion, err := parseResourceVersion(b)
  577. if err == nil {
  578. key := getPreviousResourceVersionKey(r.URL, id)
  579. previousResourceVersion[key] = currentResourceVersion
  580. }
  581. }
  582. }
  583. }()
  584. }
  585. }
  586. // TestBobIsForbidden tests that a user who is known to
  587. // the authentication system but not authorized to do any actions
  588. // should receive "Forbidden".
  589. func TestBobIsForbidden(t *testing.T) {
  590. // This file has alice and bob in it.
  591. masterConfig := framework.NewIntegrationTestMasterConfig()
  592. masterConfig.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
  593. masterConfig.GenericConfig.Authorization.Authorizer = allowAliceAuthorizer{}
  594. _, s, closeFn := framework.RunAMaster(masterConfig)
  595. defer closeFn()
  596. ns := framework.CreateTestingNamespace("auth-bob-forbidden", s, t)
  597. defer framework.DeleteTestingNamespace(ns, s, t)
  598. transport := http.DefaultTransport
  599. for _, r := range getTestRequests(ns.Name) {
  600. token := BobToken
  601. bodyBytes := bytes.NewReader([]byte(r.body))
  602. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  603. if err != nil {
  604. t.Fatalf("unexpected error: %v", err)
  605. }
  606. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  607. func() {
  608. resp, err := transport.RoundTrip(req)
  609. if err != nil {
  610. t.Logf("case %v", r)
  611. t.Fatalf("unexpected error: %v", err)
  612. }
  613. defer resp.Body.Close()
  614. // Expect all of bob's actions to return Forbidden
  615. if resp.StatusCode != http.StatusForbidden {
  616. t.Logf("case %v", r)
  617. t.Errorf("Expected not status Forbidden, but got %s", resp.Status)
  618. }
  619. }()
  620. }
  621. }
  622. // TestUnknownUserIsUnauthorized tests that a user who is unknown
  623. // to the authentication system get status code "Unauthorized".
  624. // An authorization module is installed in this scenario for integration
  625. // test purposes, but requests aren't expected to reach it.
  626. func TestUnknownUserIsUnauthorized(t *testing.T) {
  627. // This file has alice and bob in it.
  628. // Set up a master
  629. masterConfig := framework.NewIntegrationTestMasterConfig()
  630. masterConfig.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
  631. masterConfig.GenericConfig.Authorization.Authorizer = allowAliceAuthorizer{}
  632. _, s, closeFn := framework.RunAMaster(masterConfig)
  633. defer closeFn()
  634. ns := framework.CreateTestingNamespace("auth-unknown-unauthorized", s, t)
  635. defer framework.DeleteTestingNamespace(ns, s, t)
  636. transport := http.DefaultTransport
  637. for _, r := range getTestRequests(ns.Name) {
  638. token := UnknownToken
  639. bodyBytes := bytes.NewReader([]byte(r.body))
  640. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  641. if err != nil {
  642. t.Fatalf("unexpected error: %v", err)
  643. }
  644. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  645. func() {
  646. resp, err := transport.RoundTrip(req)
  647. if err != nil {
  648. t.Logf("case %v", r)
  649. t.Fatalf("unexpected error: %v", err)
  650. }
  651. defer resp.Body.Close()
  652. // Expect all of unauthenticated user's request to be "Unauthorized"
  653. if resp.StatusCode != http.StatusUnauthorized {
  654. t.Logf("case %v", r)
  655. t.Errorf("Expected status %v, but got %v", http.StatusUnauthorized, resp.StatusCode)
  656. b, _ := ioutil.ReadAll(resp.Body)
  657. t.Errorf("Body: %v", string(b))
  658. }
  659. }()
  660. }
  661. }
  662. type impersonateAuthorizer struct{}
  663. // alice can't act as anyone and bob can't do anything but act-as someone
  664. func (impersonateAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
  665. // alice can impersonate service accounts and do other actions
  666. if a.GetUser() != nil && a.GetUser().GetName() == "alice" && a.GetVerb() == "impersonate" && a.GetResource() == "serviceaccounts" {
  667. return authorizer.DecisionAllow, "", nil
  668. }
  669. if a.GetUser() != nil && a.GetUser().GetName() == "alice" && a.GetVerb() != "impersonate" {
  670. return authorizer.DecisionAllow, "", nil
  671. }
  672. // bob can impersonate anyone, but that it
  673. if a.GetUser() != nil && a.GetUser().GetName() == "bob" && a.GetVerb() == "impersonate" {
  674. return authorizer.DecisionAllow, "", nil
  675. }
  676. // service accounts can do everything
  677. if a.GetUser() != nil && strings.HasPrefix(a.GetUser().GetName(), serviceaccount.ServiceAccountUsernamePrefix) {
  678. return authorizer.DecisionAllow, "", nil
  679. }
  680. return authorizer.DecisionNoOpinion, "I can't allow that. Go ask alice.", nil
  681. }
  682. func TestImpersonateIsForbidden(t *testing.T) {
  683. // Set up a master
  684. masterConfig := framework.NewIntegrationTestMasterConfig()
  685. masterConfig.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
  686. masterConfig.GenericConfig.Authorization.Authorizer = impersonateAuthorizer{}
  687. _, s, closeFn := framework.RunAMaster(masterConfig)
  688. defer closeFn()
  689. ns := framework.CreateTestingNamespace("auth-impersonate-forbidden", s, t)
  690. defer framework.DeleteTestingNamespace(ns, s, t)
  691. transport := http.DefaultTransport
  692. // bob can't perform actions himself
  693. for _, r := range getTestRequests(ns.Name) {
  694. token := BobToken
  695. bodyBytes := bytes.NewReader([]byte(r.body))
  696. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  697. if err != nil {
  698. t.Fatalf("unexpected error: %v", err)
  699. }
  700. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  701. func() {
  702. resp, err := transport.RoundTrip(req)
  703. if err != nil {
  704. t.Logf("case %v", r)
  705. t.Fatalf("unexpected error: %v", err)
  706. }
  707. defer resp.Body.Close()
  708. // Expect all of bob's actions to return Forbidden
  709. if resp.StatusCode != http.StatusForbidden {
  710. t.Logf("case %v", r)
  711. t.Errorf("Expected not status Forbidden, but got %s", resp.Status)
  712. }
  713. }()
  714. }
  715. // bob can impersonate alice to do other things
  716. for _, r := range getTestRequests(ns.Name) {
  717. token := BobToken
  718. bodyBytes := bytes.NewReader([]byte(r.body))
  719. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  720. if err != nil {
  721. t.Fatalf("unexpected error: %v", err)
  722. }
  723. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  724. req.Header.Set("Impersonate-User", "alice")
  725. func() {
  726. resp, err := transport.RoundTrip(req)
  727. if err != nil {
  728. t.Logf("case %v", r)
  729. t.Fatalf("unexpected error: %v", err)
  730. }
  731. defer resp.Body.Close()
  732. // Expect all the requests to be allowed, don't care what they actually do
  733. if resp.StatusCode == http.StatusForbidden {
  734. t.Logf("case %v", r)
  735. t.Errorf("Expected status not %v, but got %v", http.StatusForbidden, resp.StatusCode)
  736. }
  737. }()
  738. }
  739. // alice can't impersonate bob
  740. for _, r := range getTestRequests(ns.Name) {
  741. token := AliceToken
  742. bodyBytes := bytes.NewReader([]byte(r.body))
  743. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  744. if err != nil {
  745. t.Fatalf("unexpected error: %v", err)
  746. }
  747. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  748. req.Header.Set("Impersonate-User", "bob")
  749. func() {
  750. resp, err := transport.RoundTrip(req)
  751. if err != nil {
  752. t.Logf("case %v", r)
  753. t.Fatalf("unexpected error: %v", err)
  754. }
  755. defer resp.Body.Close()
  756. // Expect all of bob's actions to return Forbidden
  757. if resp.StatusCode != http.StatusForbidden {
  758. t.Logf("case %v", r)
  759. t.Errorf("Expected not status Forbidden, but got %s", resp.Status)
  760. }
  761. }()
  762. }
  763. // alice can impersonate a service account
  764. for _, r := range getTestRequests(ns.Name) {
  765. token := BobToken
  766. bodyBytes := bytes.NewReader([]byte(r.body))
  767. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  768. if err != nil {
  769. t.Fatalf("unexpected error: %v", err)
  770. }
  771. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  772. req.Header.Set("Impersonate-User", serviceaccount.MakeUsername("default", "default"))
  773. func() {
  774. resp, err := transport.RoundTrip(req)
  775. if err != nil {
  776. t.Logf("case %v", r)
  777. t.Fatalf("unexpected error: %v", err)
  778. }
  779. defer resp.Body.Close()
  780. // Expect all the requests to be allowed, don't care what they actually do
  781. if resp.StatusCode == http.StatusForbidden {
  782. t.Logf("case %v", r)
  783. t.Errorf("Expected status not %v, but got %v", http.StatusForbidden, resp.StatusCode)
  784. }
  785. }()
  786. }
  787. }
  788. func newAuthorizerWithContents(t *testing.T, contents string) authorizer.Authorizer {
  789. f, err := ioutil.TempFile("", "auth_test")
  790. if err != nil {
  791. t.Fatalf("unexpected error creating policyfile: %v", err)
  792. }
  793. f.Close()
  794. defer os.Remove(f.Name())
  795. if err := ioutil.WriteFile(f.Name(), []byte(contents), 0700); err != nil {
  796. t.Fatalf("unexpected error writing policyfile: %v", err)
  797. }
  798. pl, err := abac.NewFromFile(f.Name())
  799. if err != nil {
  800. t.Fatalf("unexpected error creating authorizer from policyfile: %v", err)
  801. }
  802. return pl
  803. }
  804. type trackingAuthorizer struct {
  805. requestAttributes []authorizer.Attributes
  806. }
  807. func (a *trackingAuthorizer) Authorize(ctx context.Context, attributes authorizer.Attributes) (authorizer.Decision, string, error) {
  808. a.requestAttributes = append(a.requestAttributes, attributes)
  809. return authorizer.DecisionAllow, "", nil
  810. }
  811. // TestAuthorizationAttributeDetermination tests that authorization attributes are built correctly
  812. func TestAuthorizationAttributeDetermination(t *testing.T) {
  813. trackingAuthorizer := &trackingAuthorizer{}
  814. // Set up a master
  815. masterConfig := framework.NewIntegrationTestMasterConfig()
  816. masterConfig.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
  817. masterConfig.GenericConfig.Authorization.Authorizer = trackingAuthorizer
  818. _, s, closeFn := framework.RunAMaster(masterConfig)
  819. defer closeFn()
  820. ns := framework.CreateTestingNamespace("auth-attribute-determination", s, t)
  821. defer framework.DeleteTestingNamespace(ns, s, t)
  822. transport := http.DefaultTransport
  823. requests := map[string]struct {
  824. verb string
  825. URL string
  826. expectedAttributes authorizer.Attributes
  827. }{
  828. "prefix/version/resource": {"GET", "/api/v1/pods", authorizer.AttributesRecord{APIGroup: api.GroupName, Resource: "pods"}},
  829. "prefix/group/version/resource": {"GET", "/apis/extensions/v1/pods", authorizer.AttributesRecord{APIGroup: extensions.GroupName, Resource: "pods"}},
  830. "prefix/group/version/resource2": {"GET", "/apis/autoscaling/v1/horizontalpodautoscalers", authorizer.AttributesRecord{APIGroup: autoscaling.GroupName, Resource: "horizontalpodautoscalers"}},
  831. }
  832. currentAuthorizationAttributesIndex := 0
  833. for testName, r := range requests {
  834. token := BobToken
  835. req, err := http.NewRequest(r.verb, s.URL+r.URL, nil)
  836. if err != nil {
  837. t.Logf("case %v", testName)
  838. t.Fatalf("unexpected error: %v", err)
  839. }
  840. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  841. func() {
  842. resp, err := transport.RoundTrip(req)
  843. if err != nil {
  844. t.Logf("case %v", r)
  845. t.Fatalf("unexpected error: %v", err)
  846. }
  847. defer resp.Body.Close()
  848. found := false
  849. for i := currentAuthorizationAttributesIndex; i < len(trackingAuthorizer.requestAttributes); i++ {
  850. if trackingAuthorizer.requestAttributes[i].GetAPIGroup() == r.expectedAttributes.GetAPIGroup() &&
  851. trackingAuthorizer.requestAttributes[i].GetResource() == r.expectedAttributes.GetResource() {
  852. found = true
  853. break
  854. }
  855. t.Logf("%#v did not match %#v", r.expectedAttributes, trackingAuthorizer.requestAttributes[i].(*authorizer.AttributesRecord))
  856. }
  857. if !found {
  858. t.Errorf("did not find %#v in %#v", r.expectedAttributes, trackingAuthorizer.requestAttributes[currentAuthorizationAttributesIndex:])
  859. }
  860. currentAuthorizationAttributesIndex = len(trackingAuthorizer.requestAttributes)
  861. }()
  862. }
  863. }
  864. // TestNamespaceAuthorization tests that authorization can be controlled
  865. // by namespace.
  866. func TestNamespaceAuthorization(t *testing.T) {
  867. // This file has alice and bob in it.
  868. a := newAuthorizerWithContents(t, `{"namespace": "auth-namespace"}
  869. `)
  870. // Set up a master
  871. masterConfig := framework.NewIntegrationTestMasterConfig()
  872. masterConfig.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
  873. masterConfig.GenericConfig.Authorization.Authorizer = a
  874. _, s, closeFn := framework.RunAMaster(masterConfig)
  875. defer closeFn()
  876. ns := framework.CreateTestingNamespace("auth-namespace", s, t)
  877. defer framework.DeleteTestingNamespace(ns, s, t)
  878. previousResourceVersion := make(map[string]float64)
  879. transport := http.DefaultTransport
  880. requests := []struct {
  881. verb string
  882. URL string
  883. namespace string
  884. body string
  885. statusCodes map[int]bool // allowed status codes.
  886. }{
  887. {"POST", timeoutPath("pods", ns.Name, ""), "foo", aPod, integration.Code201},
  888. {"GET", path("pods", ns.Name, ""), "foo", "", integration.Code200},
  889. {"GET", path("pods", ns.Name, "a"), "foo", "", integration.Code200},
  890. {"DELETE", timeoutPath("pods", ns.Name, "a"), "foo", "", integration.Code200},
  891. {"POST", timeoutPath("pods", "foo", ""), "bar", aPod, integration.Code403},
  892. {"GET", path("pods", "foo", ""), "bar", "", integration.Code403},
  893. {"GET", path("pods", "foo", "a"), "bar", "", integration.Code403},
  894. {"DELETE", timeoutPath("pods", "foo", "a"), "bar", "", integration.Code403},
  895. {"POST", timeoutPath("pods", metav1.NamespaceDefault, ""), "", aPod, integration.Code403},
  896. {"GET", path("pods", "", ""), "", "", integration.Code403},
  897. {"GET", path("pods", metav1.NamespaceDefault, "a"), "", "", integration.Code403},
  898. {"DELETE", timeoutPath("pods", metav1.NamespaceDefault, "a"), "", "", integration.Code403},
  899. }
  900. for _, r := range requests {
  901. token := BobToken
  902. var bodyStr string
  903. if r.body != "" {
  904. sub := ""
  905. if r.verb == "PUT" && r.body != "" {
  906. // For update operations, insert previous resource version
  907. if resVersion := previousResourceVersion[getPreviousResourceVersionKey(r.URL, "")]; resVersion != 0 {
  908. sub += fmt.Sprintf(",\r\n\"resourceVersion\": \"%v\"", resVersion)
  909. }
  910. namespace := r.namespace
  911. // FIXME: Is that correct?
  912. if len(namespace) == 0 {
  913. namespace = "default"
  914. }
  915. sub += fmt.Sprintf(",\r\n\"namespace\": %q", namespace)
  916. }
  917. bodyStr = fmt.Sprintf(r.body, sub)
  918. }
  919. r.body = bodyStr
  920. bodyBytes := bytes.NewReader([]byte(bodyStr))
  921. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  922. if err != nil {
  923. t.Logf("case %v", r)
  924. t.Fatalf("unexpected error: %v", err)
  925. }
  926. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  927. func() {
  928. resp, err := transport.RoundTrip(req)
  929. if err != nil {
  930. t.Logf("case %v", r)
  931. t.Fatalf("unexpected error: %v", err)
  932. }
  933. defer resp.Body.Close()
  934. b, _ := ioutil.ReadAll(resp.Body)
  935. if _, ok := r.statusCodes[resp.StatusCode]; !ok {
  936. t.Logf("case %v", r)
  937. t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode)
  938. t.Errorf("Body: %v", string(b))
  939. } else {
  940. if r.verb == "POST" {
  941. // For successful create operations, extract resourceVersion
  942. id, currentResourceVersion, err := parseResourceVersion(b)
  943. if err == nil {
  944. key := getPreviousResourceVersionKey(r.URL, id)
  945. previousResourceVersion[key] = currentResourceVersion
  946. }
  947. }
  948. }
  949. }()
  950. }
  951. }
  952. // TestKindAuthorization tests that authorization can be controlled
  953. // by namespace.
  954. func TestKindAuthorization(t *testing.T) {
  955. // This file has alice and bob in it.
  956. a := newAuthorizerWithContents(t, `{"resource": "services"}
  957. `)
  958. // Set up a master
  959. masterConfig := framework.NewIntegrationTestMasterConfig()
  960. masterConfig.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
  961. masterConfig.GenericConfig.Authorization.Authorizer = a
  962. _, s, closeFn := framework.RunAMaster(masterConfig)
  963. defer closeFn()
  964. ns := framework.CreateTestingNamespace("auth-kind", s, t)
  965. defer framework.DeleteTestingNamespace(ns, s, t)
  966. previousResourceVersion := make(map[string]float64)
  967. transport := http.DefaultTransport
  968. requests := []struct {
  969. verb string
  970. URL string
  971. body string
  972. statusCodes map[int]bool // allowed status codes.
  973. }{
  974. {"POST", timeoutPath("services", ns.Name, ""), aService, integration.Code201},
  975. {"GET", path("services", ns.Name, ""), "", integration.Code200},
  976. {"GET", path("services", ns.Name, "a"), "", integration.Code200},
  977. {"DELETE", timeoutPath("services", ns.Name, "a"), "", integration.Code200},
  978. {"POST", timeoutPath("pods", ns.Name, ""), aPod, integration.Code403},
  979. {"GET", path("pods", "", ""), "", integration.Code403},
  980. {"GET", path("pods", ns.Name, "a"), "", integration.Code403},
  981. {"DELETE", timeoutPath("pods", ns.Name, "a"), "", integration.Code403},
  982. }
  983. for _, r := range requests {
  984. token := BobToken
  985. var bodyStr string
  986. if r.body != "" {
  987. bodyStr = fmt.Sprintf(r.body, "")
  988. if r.verb == "PUT" && r.body != "" {
  989. // For update operations, insert previous resource version
  990. if resVersion := previousResourceVersion[getPreviousResourceVersionKey(r.URL, "")]; resVersion != 0 {
  991. resourceVersionJSON := fmt.Sprintf(",\r\n\"resourceVersion\": \"%v\"", resVersion)
  992. bodyStr = fmt.Sprintf(r.body, resourceVersionJSON)
  993. }
  994. }
  995. }
  996. r.body = bodyStr
  997. bodyBytes := bytes.NewReader([]byte(bodyStr))
  998. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  999. if err != nil {
  1000. t.Logf("case %v", r)
  1001. t.Fatalf("unexpected error: %v", err)
  1002. }
  1003. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  1004. {
  1005. resp, err := transport.RoundTrip(req)
  1006. if err != nil {
  1007. t.Logf("case %v", r)
  1008. t.Fatalf("unexpected error: %v", err)
  1009. }
  1010. defer resp.Body.Close()
  1011. b, _ := ioutil.ReadAll(resp.Body)
  1012. if _, ok := r.statusCodes[resp.StatusCode]; !ok {
  1013. t.Logf("case %v", r)
  1014. t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode)
  1015. t.Errorf("Body: %v", string(b))
  1016. } else {
  1017. if r.verb == "POST" {
  1018. // For successful create operations, extract resourceVersion
  1019. id, currentResourceVersion, err := parseResourceVersion(b)
  1020. if err == nil {
  1021. key := getPreviousResourceVersionKey(r.URL, id)
  1022. previousResourceVersion[key] = currentResourceVersion
  1023. }
  1024. }
  1025. }
  1026. }
  1027. }
  1028. }
  1029. // TestReadOnlyAuthorization tests that authorization can be controlled
  1030. // by namespace.
  1031. func TestReadOnlyAuthorization(t *testing.T) {
  1032. // This file has alice and bob in it.
  1033. a := newAuthorizerWithContents(t, `{"readonly": true}`)
  1034. // Set up a master
  1035. masterConfig := framework.NewIntegrationTestMasterConfig()
  1036. masterConfig.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
  1037. masterConfig.GenericConfig.Authorization.Authorizer = a
  1038. _, s, closeFn := framework.RunAMaster(masterConfig)
  1039. defer closeFn()
  1040. ns := framework.CreateTestingNamespace("auth-read-only", s, t)
  1041. defer framework.DeleteTestingNamespace(ns, s, t)
  1042. transport := http.DefaultTransport
  1043. requests := []struct {
  1044. verb string
  1045. URL string
  1046. body string
  1047. statusCodes map[int]bool // allowed status codes.
  1048. }{
  1049. {"POST", path("pods", ns.Name, ""), aPod, integration.Code403},
  1050. {"GET", path("pods", ns.Name, ""), "", integration.Code200},
  1051. {"GET", path("pods", metav1.NamespaceDefault, "a"), "", integration.Code404},
  1052. }
  1053. for _, r := range requests {
  1054. token := BobToken
  1055. bodyBytes := bytes.NewReader([]byte(r.body))
  1056. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  1057. if err != nil {
  1058. t.Fatalf("unexpected error: %v", err)
  1059. }
  1060. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  1061. func() {
  1062. resp, err := transport.RoundTrip(req)
  1063. if err != nil {
  1064. t.Logf("case %v", r)
  1065. t.Fatalf("unexpected error: %v", err)
  1066. }
  1067. defer resp.Body.Close()
  1068. if _, ok := r.statusCodes[resp.StatusCode]; !ok {
  1069. t.Logf("case %v", r)
  1070. t.Errorf("Expected status one of %v, but got %v", r.statusCodes, resp.StatusCode)
  1071. b, _ := ioutil.ReadAll(resp.Body)
  1072. t.Errorf("Body: %v", string(b))
  1073. }
  1074. }()
  1075. }
  1076. }
  1077. // TestWebhookTokenAuthenticator tests that a master can use the webhook token
  1078. // authenticator to call out to a remote web server for authentication
  1079. // decisions.
  1080. func TestWebhookTokenAuthenticator(t *testing.T) {
  1081. authServer := newTestWebhookTokenAuthServer()
  1082. defer authServer.Close()
  1083. authenticator, err := getTestWebhookTokenAuth(authServer.URL)
  1084. if err != nil {
  1085. t.Fatalf("error starting webhook token authenticator server: %v", err)
  1086. }
  1087. // Set up a master
  1088. masterConfig := framework.NewIntegrationTestMasterConfig()
  1089. masterConfig.GenericConfig.Authentication.Authenticator = authenticator
  1090. masterConfig.GenericConfig.Authorization.Authorizer = allowAliceAuthorizer{}
  1091. _, s, closeFn := framework.RunAMaster(masterConfig)
  1092. defer closeFn()
  1093. ns := framework.CreateTestingNamespace("auth-webhook-token", s, t)
  1094. defer framework.DeleteTestingNamespace(ns, s, t)
  1095. transport := http.DefaultTransport
  1096. for _, r := range getTestRequests(ns.Name) {
  1097. // Expect Bob's requests to all fail.
  1098. token := BobToken
  1099. bodyBytes := bytes.NewReader([]byte(r.body))
  1100. req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  1101. if err != nil {
  1102. t.Fatalf("unexpected error: %v", err)
  1103. }
  1104. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  1105. func() {
  1106. resp, err := transport.RoundTrip(req)
  1107. if err != nil {
  1108. t.Logf("case %v", r)
  1109. t.Fatalf("unexpected error: %v", err)
  1110. }
  1111. defer resp.Body.Close()
  1112. // Expect all of Bob's actions to return Forbidden
  1113. if resp.StatusCode != http.StatusForbidden {
  1114. t.Logf("case %v", r)
  1115. t.Errorf("Expected http.Forbidden, but got %s", resp.Status)
  1116. }
  1117. }()
  1118. // Expect Alice's requests to succeed.
  1119. token = AliceToken
  1120. bodyBytes = bytes.NewReader([]byte(r.body))
  1121. req, err = http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
  1122. if err != nil {
  1123. t.Fatalf("unexpected error: %v", err)
  1124. }
  1125. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
  1126. func() {
  1127. resp, err := transport.RoundTrip(req)
  1128. if err != nil {
  1129. t.Logf("case %v", r)
  1130. t.Fatalf("unexpected error: %v", err)
  1131. }
  1132. defer resp.Body.Close()
  1133. // Expect all of Alice's actions to at least get past authn/authz.
  1134. if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
  1135. t.Logf("case %v", r)
  1136. t.Errorf("Expected something other than Unauthorized/Forbidden, but got %s", resp.Status)
  1137. }
  1138. }()
  1139. }
  1140. }
  1141. // newTestWebhookTokenAuthServer creates an http token authentication server
  1142. // that knows about both Alice and Bob.
  1143. func newTestWebhookTokenAuthServer() *httptest.Server {
  1144. serveHTTP := func(w http.ResponseWriter, r *http.Request) {
  1145. var review authenticationv1beta1.TokenReview
  1146. if err := json.NewDecoder(r.Body).Decode(&review); err != nil {
  1147. http.Error(w, fmt.Sprintf("failed to decode body: %v", err), http.StatusBadRequest)
  1148. return
  1149. }
  1150. type userInfo struct {
  1151. Username string `json:"username"`
  1152. UID string `json:"uid"`
  1153. Groups []string `json:"groups"`
  1154. }
  1155. type status struct {
  1156. Authenticated bool `json:"authenticated"`
  1157. User userInfo `json:"user"`
  1158. }
  1159. var username, uid string
  1160. authenticated := false
  1161. if review.Spec.Token == AliceToken {
  1162. authenticated, username, uid = true, "alice", "1"
  1163. } else if review.Spec.Token == BobToken {
  1164. authenticated, username, uid = true, "bob", "2"
  1165. }
  1166. resp := struct {
  1167. APIVersion string `json:"apiVersion"`
  1168. Status status `json:"status"`
  1169. }{
  1170. APIVersion: authenticationv1beta1.SchemeGroupVersion.String(),
  1171. Status: status{
  1172. authenticated,
  1173. userInfo{
  1174. Username: username,
  1175. UID: uid,
  1176. },
  1177. },
  1178. }
  1179. w.Header().Set("Content-Type", "application/json")
  1180. json.NewEncoder(w).Encode(resp)
  1181. }
  1182. server := httptest.NewUnstartedServer(http.HandlerFunc(serveHTTP))
  1183. server.Start()
  1184. return server
  1185. }