File kubelogin-0.2.10.obscpio of Package kubelogin

07070100000000000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001800000000kubelogin-0.2.10/.bingo07070100000001000081A4000000000000000000000001687816E50000007B000000000000000000000000000000000000002300000000kubelogin-0.2.10/.bingo/.gitignore
# Ignore everything
*

# But not these files:
!.gitignore
!*.mod
!*.sum
!README.md
!Variables.mk
!variables.env

*tmp.mod
07070100000002000081A4000000000000000000000001687816E500000334000000000000000000000000000000000000002200000000kubelogin-0.2.10/.bingo/README.md# Project Development Dependencies.

This is directory which stores Go modules with pinned buildable package that is used within this repository, managed by https://github.com/bwplotka/bingo.

* Run `bingo get` to install all tools having each own module file in this directory.
* Run `bingo get <tool>` to install <tool> that have own module file in this directory.
* For Makefile: Make sure to put `include .bingo/Variables.mk` in your Makefile, then use $(<upper case tool name>) variable where <tool> is the .bingo/<tool>.mod.
* For shell: Run `source .bingo/variables.env` to source all environment variable for each tool.
* For go: Import `.bingo/variables.go` to for variable names.
* See https://github.com/bwplotka/bingo or -h on how to add, remove or change binaries dependencies.

## Requirements

* Go 1.14+
07070100000003000081A4000000000000000000000001687816E5000004A9000000000000000000000000000000000000002500000000kubelogin-0.2.10/.bingo/Variables.mk# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.9. DO NOT EDIT.
# All tools are designed to be build inside $GOBIN.
BINGO_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
GOPATH ?= $(shell go env GOPATH)
GOBIN  ?= $(firstword $(subst :, ,${GOPATH}))/bin
GO     ?= $(shell which go)

# Below generated variables ensure that every time a tool under each variable is invoked, the correct version
# will be used; reinstalling only if needed.
# For example for golangci-lint variable:
#
# In your main Makefile (for non array binaries):
#
#include .bingo/Variables.mk # Assuming -dir was set to .bingo .
#
#command: $(GOLANGCI_LINT)
#	@echo "Running golangci-lint"
#	@$(GOLANGCI_LINT) <flags/args..>
#
GOLANGCI_LINT := $(GOBIN)/golangci-lint-v1.62.2
$(GOLANGCI_LINT): $(BINGO_DIR)/golangci-lint.mod
	@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
	@echo "(re)installing $(GOBIN)/golangci-lint-v1.62.2"
	@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=golangci-lint.mod -o=$(GOBIN)/golangci-lint-v1.62.2 "github.com/golangci/golangci-lint/cmd/golangci-lint"

07070100000004000081A4000000000000000000000001687816E500000094000000000000000000000000000000000000001F00000000kubelogin-0.2.10/.bingo/go.modmodule _ // Fake go.mod auto-created by 'bingo' for go -moddir compatibility with non-Go projects. Commit this file, together with other .mod files.07070100000005000081A4000000000000000000000001687816E5000000A1000000000000000000000000000000000000002A00000000kubelogin-0.2.10/.bingo/golangci-lint.modmodule _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT

go 1.22.10

require github.com/golangci/golangci-lint v1.62.2 // cmd/golangci-lint
07070100000006000081A4000000000000000000000001687816E500015603000000000000000000000000000000000000002A00000000kubelogin-0.2.10/.bingo/golangci-lint.sum4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA=
4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs=
4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc=
4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8=
github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0=
github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE=
github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw=
github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA=
github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI=
github.com/Antonboom/nilnil v1.0.0 h1:n+v+B12dsE5tbAqRODXmEKfZv9j2KcTBrp+LkoM4HZk=
github.com/Antonboom/nilnil v1.0.0/go.mod h1:fDJ1FSFoLN6yoG65ANb1WihItf6qt9PJVTn/s2IrcII=
github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk=
github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Crocmagnon/fatcontext v0.5.3 h1:zCh/wjc9oyeF+Gmp+V60wetm8ph2tlsxocgg/J0hOps=
github.com/Crocmagnon/fatcontext v0.5.3/go.mod h1:XoCQYY1J+XTfyv74qLXvNw4xFunr3L1wkopIIKG7wGM=
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM=
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU=
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao=
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA=
github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ=
github.com/alecthomas/go-check-sumtype v0.2.0 h1:Bo+e4DFf3rs7ME9w/0SU/g6nmzJaphduP8Cjiz0gbwY=
github.com/alecthomas/go-check-sumtype v0.2.0/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alexkohler/nakedret/v2 v2.0.5 h1:fP5qLgtwbx9EJE8dGEERT02YwS8En4r9nnZ71RK+EVU=
github.com/alexkohler/nakedret/v2 v2.0.5/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU=
github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw=
github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw=
github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I=
github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY=
github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU=
github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s=
github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w=
github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo=
github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M=
github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw=
github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo=
github.com/breml/bidichk v0.3.2 h1:xV4flJ9V5xWTqxL+/PMFF6dtJPvZLPsyixAoPe8BGJs=
github.com/breml/bidichk v0.3.2/go.mod h1:VzFLBxuYtT23z5+iVkamXO386OB+/sVwZOpIj6zXGos=
github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk=
github.com/breml/errchkjson v0.4.0/go.mod h1:AuBOSTHyLSaaAFlWsRSuRBIroCh3eh7ZHh5YeelDIk8=
github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0=
github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA=
github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs=
github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ=
github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyyTJ/rMmc=
github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50=
github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg=
github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4=
github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/ckaznocha/intrange v0.2.1 h1:M07spnNEQoALOJhwrImSrJLaxwuiQK+hA2DeajBlwYk=
github.com/ckaznocha/intrange v0.2.1/go.mod h1:7NEhVyf8fzZO5Ds7CRaqPEm52Ut83hsTiL5zbER/HYk=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo=
github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc=
github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c=
github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=
github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q=
github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA=
github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
github.com/ghostiam/protogetter v0.3.8 h1:LYcXbYvybUyTIxN2Mj9h6rHrDZBDwZloPoKctWrFyJY=
github.com/ghostiam/protogetter v0.3.8/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA=
github.com/go-critic/go-critic v0.11.5 h1:TkDTOn5v7EEngMxu8KbuFqFR43USaaH8XRJLz1jhVYA=
github.com/go-critic/go-critic v0.11.5/go.mod h1:wu6U7ny9PiaHaZHcvMDmdysMqvDem162Rh3zWTrqk8M=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8=
github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU=
github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s=
github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw=
github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=
github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ=
github.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw=
github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY=
github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco=
github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4=
github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA=
github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA=
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw=
github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=
github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U=
github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUPPyAKJuzv8pEJU=
github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s=
github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME=
github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE=
github.com/golangci/golangci-lint v1.62.2 h1:b8K5K9PN+rZN1+mKLtsZHz2XXS9aYKzQ9i25x3Qnxxw=
github.com/golangci/golangci-lint v1.62.2/go.mod h1:ILWWyeFUrctpHVGMa1dg2xZPKoMUTc5OIMgW7HZr34g=
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA=
github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM=
github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c=
github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc=
github.com/golangci/revgrep v0.5.3 h1:3tL7c1XBMtWHHqVpS5ChmiAAoe4PF/d5+ULzV9sLAzs=
github.com/golangci/revgrep v0.5.3/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k=
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs=
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s=
github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk=
github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc=
github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado=
github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q=
github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM=
github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70=
github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak=
github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk=
github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A=
github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk=
github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=
github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk=
github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY=
github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0=
github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos=
github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k=
github.com/kisielk/errcheck v1.8.0 h1:ZX/URYa7ilESY19ik/vBmCn6zdGQLxACwjAcWbHlYlg=
github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg=
github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs=
github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I=
github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs=
github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY=
github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ=
github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA=
github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4=
github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI=
github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg=
github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g=
github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo=
github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4=
github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY=
github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk=
github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI=
github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc=
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE=
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mgechev/revive v1.5.1 h1:hE+QPeq0/wIzJwOphdVyUJ82njdd8Khp4fUIHGZHW3M=
github.com/mgechev/revive v1.5.1/go.mod h1:lC9AhkJIBs5zwx8wkudyHrU+IJkrEKmpCmGMnIJPk4o=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI=
github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U=
github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE=
github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg=
github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs=
github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk=
github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
github.com/nunnatsa/ginkgolinter v0.18.3 h1:WgS7X3zzmni3vwHSBhvSgqrRgUecN6PQUcfB0j1noDw=
github.com/nunnatsa/ginkgolinter v0.18.3/go.mod h1:BE1xyB/PNtXXG1azrvrqJW5eFH0hSRylNzFy8QHPwzs=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/polyfloyd/go-errorlint v1.7.0 h1:Zp6lzCK4hpBDj8y8a237YK4EPrMXQWvOe3nGoH4pFrU=
github.com/polyfloyd/go-errorlint v1.7.0/go.mod h1:dGWKu85mGHnegQ2SWpEybFityCg3j7ZbwsVUxAOk9gY=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo=
github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI=
github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE=
github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo=
github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng=
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU=
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
github.com/raeperd/recvcheck v0.1.2 h1:SjdquRsRXJc26eSonWIo8b7IMtKD3OAT2Lb5G3ZX1+4=
github.com/raeperd/recvcheck v0.1.2/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU=
github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE=
github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=
github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc=
github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw=
github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=
github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI=
github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8=
github.com/securego/gosec/v2 v2.21.4 h1:Le8MSj0PDmOnHJgUATjD96PaXRvCpKC+DGJvwyy0Mlk=
github.com/securego/gosec/v2 v2.21.4/go.mod h1:Jtb/MwRQfRxCXyCm1rfM1BEiiiTfUOdyzzAhlr6lUTA=
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU=
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE=
github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4=
github.com/sivchari/tenv v1.12.1 h1:+E0QzjktdnExv/wwsnnyk4oqZBUfuh89YMQT1cyuvSY=
github.com/sivchari/tenv v1.12.1/go.mod h1:1LjSOUCc25snIr5n3DtGGrENhX3LuWefcplwVGC24mw=
github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM=
github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c=
github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc=
github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM=
github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg=
github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
github.com/tetafro/godot v1.4.18 h1:ouX3XGiziKDypbpXqShBfnNLTSjR8r3/HVzrtJ+bHlI=
github.com/tetafro/godot v1.4.18/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M=
github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ=
github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg=
github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8=
github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4=
github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo=
github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw=
github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI=
github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4=
github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ=
github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8=
github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM=
github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U=
github.com/uudashr/iface v1.2.1 h1:vHHyzAUmWZ64Olq6NZT3vg/z1Ws56kyPdBOd5kTXDF8=
github.com/uudashr/iface v1.2.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk=
github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs=
github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4=
github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw=
github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo=
gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8=
go-simpler.org/musttag v0.13.0 h1:Q/YAW0AHvaoaIbsPj3bvEI5/QFP7w696IMUpnKXQfCE=
go-simpler.org/musttag v0.13.0/go.mod h1:FTzIGeK6OkKlUDVpj0iQUXZLUO1Js9+mvykDQy9C5yM=
go-simpler.org/sloglint v0.7.2 h1:Wc9Em/Zeuu7JYpl+oKoYOsQSy2X560aVueCW/m6IijY=
go-simpler.org/sloglint v0.7.2/go.mod h1:US+9C80ppl7VsThQclkM7BkCHQAzuz8kHLsW3ppuluo=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f h1:WTyX8eCCyfdqiPYkRGm0MqElSfYFH3yR1+rl/mct9sA=
golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=
honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs=
mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU=
mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo=
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U=
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
07070100000007000081A4000000000000000000000001687816E5000001A2000000000000000000000000000000000000002600000000kubelogin-0.2.10/.bingo/variables.env# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.9. DO NOT EDIT.
# All tools are designed to be build inside $GOBIN.
# Those variables will work only until 'bingo get' was invoked, or if tools were installed via Makefile's Variables.mk.
GOBIN=${GOBIN:=$(go env GOBIN)}

if [ -z "$GOBIN" ]; then
	GOBIN="$(go env GOPATH)/bin"
fi


GOLANGCI_LINT="${GOBIN}/golangci-lint-v1.62.2"

07070100000008000081A4000000000000000000000001687816E500000252000000000000000000000000000000000000001F00000000kubelogin-0.2.10/.dockerignore# Docker ignore file for kubelogin
# Ignore development and build files that are not needed in Docker context

# Version control
.git
.gitignore

# Build artifacts (except the final binary)
.bingo/
hack/

# Documentation
docs/
README.md
CHANGELOG.md
CODE_OF_CONDUCT.md
SECURITY.md

# Test files
*_test.go
**/*_test.go
**/testdata/
**/*VCR.yaml

# Development files
.github/dependabot.yml
.github/workflows/golangci-lint.yml
.github/workflows/website.yaml
.github/workflows/dependency-review.yml
.pre-commit-config.yaml

# IDE files
.vscode/
.idea/
*.swp
*.swo
*~

# OS files
.DS_Store
Thumbs.db07070100000009000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001900000000kubelogin-0.2.10/.github0707010000000A000081A4000000000000000000000001687816E500000243000000000000000000000000000000000000002800000000kubelogin-0.2.10/.github/dependabot.yml# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: "gomod" # See documentation for possible values
  directory: "/" # Location of package manifests
  schedule:
    interval: "daily"

- package-ecosystem: github-actions
  directory: /
  schedule:
    interval: daily
0707010000000B000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002300000000kubelogin-0.2.10/.github/workflows0707010000000C000081A4000000000000000000000001687816E500000A5D000000000000000000000000000000000000002D00000000kubelogin-0.2.10/.github/workflows/build.ymlname: Build on Push
on:
  push:
    paths-ignore:
      - docs/**
      - README.md
  pull_request:
    branches:
      - main
    paths-ignore:
      - docs/**
      - README.md

permissions:
  contents: read

jobs:
  test:
    name: Test
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      deployments: read
      packages: none
    env:
      GO111MODULE: on
    steps:
      - name: Check out code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Set up Go
        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
        with:
          go-version-file: "go.mod"
          cache: false

      - name: Run tests
        run: make test

      - name: Upload coverage reports to Codecov
        uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2

  build-linux-and-windows:
    name: Build Linux and Windows
    runs-on: ubuntu-latest
    needs: test
    steps:
      - name: Check out code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Set up Go
        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
        with:
          go-version-file: "go.mod"
          cache: false

      - name: Build Linux AMD64
        run: make
        env:
          GOOS: linux
          GOARCH: amd64
          CGO_ENABLED: 0

      - name: Build Linux ARM64
        run: make
        env:
          GOOS: linux
          GOARCH: arm64
          CGO_ENABLED: 0

      - name: Build Linux ARMv7
        run: make
        env:
          GOOS: linux
          GOARCH: arm
          GOARM: "7"
          CGO_ENABLED: 0
      
      - name: Build Windows AMD64
        run: make
        env:
          GOOS: windows
          GOARCH: amd64
          CGO_ENABLED: 0
  
      - name: Build Windows ARM64
        run: make
        env:
          GOOS: windows
          GOARCH: arm64
          CGO_ENABLED: 0

  build-macos:
    name: Build macOS
    runs-on: macos-latest
    needs: test
    steps:
      - name: Check out code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Set up Go
        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
        with:
          go-version-file: "go.mod"
          cache: false

      - name: Build macOS AMD64
        run: make
        env:
          GOOS: darwin
          GOARCH: amd64
          CGO_ENABLED: 1

      - name: Build macOS ARM64
        run: make
        env:
          GOOS: darwin
          GOARCH: arm64
          CGO_ENABLED: 1
0707010000000D000081A4000000000000000000000001687816E500000323000000000000000000000000000000000000003900000000kubelogin-0.2.10/.github/workflows/dependency-review.yml# Dependency Review Action
#
# This Action will scan dependency manifest files that change as part of a Pull Request,
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
# Once installed, if the workflow run is marked as required,
# PRs introducing known-vulnerable packages will be blocked from merging.
#
# Source repository: https://github.com/actions/dependency-review-action
name: 'Dependency Review'
on: [pull_request]

permissions:
  contents: read

jobs:
  dependency-review:
    runs-on: ubuntu-latest
    steps:
      - name: 'Checkout Repository'
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
      - name: 'Dependency Review'
        uses: actions/dependency-review-action@0efb1d1d84fc9633afcdaad14c485cbbc90ef46c # v2.5.1
0707010000000E000081A4000000000000000000000001687816E500000BA2000000000000000000000000000000000000003600000000kubelogin-0.2.10/.github/workflows/docker-publish.ymlname: Docker Build and Publish

on:
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      tag:
        description: 'Docker image tag'
        required: false
        default: 'latest'

permissions:
  contents: read
  packages: write

env:
  REGISTRY: ghcr.io

jobs:
  docker:
    name: Build and Publish Docker Image
    runs-on: ubuntu-latest
    steps:
      - name: Set IMAGE_NAME to lowercase
        run: echo "IMAGE_NAME=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV

      - name: Check out code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Set up Go
        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
        with:
          go-version-file: "go.mod"
          cache: false

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract release tag
        id: extract_tag
        run: |
          if [ "${{ github.event_name }}" = "release" ]; then
            echo "tag=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
          else
            echo "tag=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
          fi

      - name: Build kubelogin binaries for multi-arch
        run: |
          # Build for amd64
          GOOS=linux GOARCH=amd64 CGO_ENABLED=0 GIT_TAG=${{ steps.extract_tag.outputs.tag }} make kubelogin
          
          # Build for arm64  
          GOOS=linux GOARCH=arm64 CGO_ENABLED=0 GIT_TAG=${{ steps.extract_tag.outputs.tag }} make kubelogin
          
          # Verify binaries were created
          ls -la bin/linux_amd64/kubelogin
          ls -la bin/linux_arm64/kubelogin
          
          # Test the binaries
          file bin/linux_amd64/kubelogin
          file bin/linux_arm64/kubelogin

      - name: Build and push Docker image
        uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.extract_tag.outputs.tag }}
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
          file: Dockerfile

      - name: Generate Docker image summary
        run: |
          echo "## Docker Image Published" >> $GITHUB_STEP_SUMMARY
          echo "- **Registry**: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" >> $GITHUB_STEP_SUMMARY
          echo "- **Tag**: ${{ steps.extract_tag.outputs.tag }}" >> $GITHUB_STEP_SUMMARY
          echo "- **Platforms**: linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY0707010000000F000081A4000000000000000000000001687816E500000404000000000000000000000000000000000000003500000000kubelogin-0.2.10/.github/workflows/golangci-lint.ymlname: golangci-lint
on:
  push:
    tags:
      - v*
    branches:
      - main
    paths-ignore:
      - docs/**
      - README.md
  pull_request:
    paths-ignore:
      - docs/**
      - README.md
permissions:
  contents: read
  # Optional: allow read access to pull request. Use with `only-new-issues` option.
  # pull-requests: read
jobs:
  golangci:
    name: lint
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      deployments: read
      packages: none
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
        with:
          go-version-file: "go.mod"
          cache: false
      - name: golangci-lint
        uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
        with:
          # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
          version: v1.62.2
07070100000010000081A4000000000000000000000001687816E500002337000000000000000000000000000000000000002F00000000kubelogin-0.2.10/.github/workflows/release.ymlname: Release
on:
  workflow_dispatch:

permissions:
  contents: read

jobs:
  create-release:
    name: Create Release
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: write
      deployments: read
      packages: none
    outputs:
      release_id: ${{ steps.create_release.outputs.id }}
      tag_version: "v${{ steps.changelog_reader.outputs.version }}"
    steps:
      - name: Check out code into the Go module directory
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
        
      # Read changelog and read versions etc.
      - name: Check version is mentioned in Changelog.md
        id: changelog_reader
        uses: mindsers/changelog-reader-action@b97ce03a10d9bdbb07beb491c76a5a01d78cd3ef # v2.2.2
        with:
          validation_depth: 10
          path: "CHANGELOG.md"

      # Check if the newest tag already exists
      - name: Check if tag exist
        uses: mukunku/tag-exists-action@bdad1eaa119ce71b150b952c97351c75025c06a9 # v1.6.0
        id: check-tag-exists
        with:
          tag: "v${{ steps.changelog_reader.outputs.version }} release"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      # Create Draft Release
      - name: Create Kubelogin Draft Release
        id: create_release
        if: ${{ steps.check-tag-exists.outputs.exists == 'false'}}
        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: "v${{ steps.changelog_reader.outputs.version }}"
          name: "v${{ steps.changelog_reader.outputs.version }} release"
          body: ${{ steps.changelog_reader.outputs.changes }}
          draft: true

  build-linux-and-windows:
    name: Build Linux and Windows
    runs-on: ubuntu-latest
    needs: create-release
    if: ${{ needs.create-release.outputs.release_id != '' }}
    steps:
      - name: Check out code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Get tags
        run: git fetch --tags

      - name: Set up Go
        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
        with:
          go-version-file: "go.mod"
          cache: false

      - name: Build Linux AMD64
        run: make
        env:
          GOOS: linux
          GOARCH: amd64
          CGO_ENABLED: 0
          GIT_TAG: "${{ needs.create-release.outputs.tag_version }}"

      - name: Build Linux ARM64
        run: make
        env:
          GOOS: linux
          GOARCH: arm64
          CGO_ENABLED: 0
          GIT_TAG: "${{ needs.create-release.outputs.tag_version }}"

      - name: Build Linux ARMv7
        run: make
        env:
          GOOS: linux
          GOARCH: arm
          GOARM: "7"
          CGO_ENABLED: 0
          GIT_TAG: "${{ needs.create-release.outputs.tag_version }}"
      
      - name: Build Windows AMD64
        run: make
        env:
          GOOS: windows
          GOARCH: amd64
          CGO_ENABLED: 0
          GIT_TAG: "${{ needs.create-release.outputs.tag_version }}"
    
      - name: Build Windows ARM64
        run: make
        env:
          GOOS: windows
          GOARCH: arm64
          CGO_ENABLED: 0
          GIT_TAG: "${{ needs.create-release.outputs.tag_version }}"

      - name: tarball Linux binaries
        run: |
          tar -czf linux-kubelogin.tar.gz bin/linux_*
      
      - name: tarball windows binaries
        run: |
          tar -czf windows-kubelogin.tar.gz bin/windows_*

      - name: Upload Linux artifacts
        uses: actions/upload-artifact@v4
        with:
          name: linux-binaries
          path: linux-kubelogin.tar.gz
      
      - name: Upload Windows artifacts
        uses: actions/upload-artifact@v4
        with:
          name: windows-binaries
          path: windows-kubelogin.tar.gz

  build-macos:
    name: Build macOS
    runs-on: macos-latest
    needs: create-release
    if: ${{ needs.create-release.outputs.release_id != '' }}
    steps:
      - name: Check out code
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

      - name: Get tags
        run: git fetch --tags

      - name: Set up Go
        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
        with:
          go-version-file: "go.mod"
          cache: false

      - name: Build macOS AMD64
        run: make
        env:
          GOOS: darwin
          GOARCH: amd64
          CGO_ENABLED: 1
          GIT_TAG: "${{ needs.create-release.outputs.tag_version }}"

      - name: Build macOS ARM64
        run: make
        env:
          GOOS: darwin
          GOARCH: arm64
          CGO_ENABLED: 1
          GIT_TAG: "${{ needs.create-release.outputs.tag_version }}"

      - name: tarball macos binaries
        run: |
          tar -czf macos-kubelogin.tar.gz bin/darwin_*

      - name: Upload macOS artifacts
        uses: actions/upload-artifact@v4
        with:
          name: macos-binaries
          path: macos-kubelogin.tar.gz

  package-and-publish:
    name: Package and Publish
    runs-on: ubuntu-latest
    permissions:
      contents: write
    needs: [create-release, build-linux-and-windows, build-macos]
    if: ${{ needs.create-release.outputs.release_id != '' }}
    steps:
      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          path: bin

      - name: untar binaries
        run: |
          tar -xzf bin/linux-binaries/linux-kubelogin.tar.gz
          tar -xzf bin/macos-binaries/macos-kubelogin.tar.gz
          tar -xzf bin/windows-binaries/windows-kubelogin.tar.gz

      - name: Move binaries to correct locations
        run: |
          mkdir -p bin/linux_amd64 bin/linux_arm64 bin/linux_armv7 \
                 bin/darwin_amd64 bin/darwin_arm64 \
                 bin/windows_amd64 bin/windows_arm64
          rm -rf bin/linux-binaries bin/macos-binaries bin/windows-binaries

      - name: Zip
        uses: montudor/action-zip@a8e75c9faefcd80fac3baf53ef40b9b119d5b702 # v1
        with:
          args: zip -qq -r kubelogin.zip bin

      - name: Zip (win-amd64)
        uses: montudor/action-zip@a8e75c9faefcd80fac3baf53ef40b9b119d5b702 # v1
        with:
          args: zip -qq kubelogin-win-amd64.zip bin/windows_amd64/kubelogin.exe

      - name: Zip (win-arm64)
        uses: montudor/action-zip@a8e75c9faefcd80fac3baf53ef40b9b119d5b702 # v1
        with:
          args: zip -qq kubelogin-win-arm64.zip bin/windows_arm64/kubelogin.exe

      - name: Zip (darwin-amd64)
        uses: montudor/action-zip@a8e75c9faefcd80fac3baf53ef40b9b119d5b702 # v1
        with:
          args: zip -qq kubelogin-darwin-amd64.zip bin/darwin_amd64/kubelogin

      - name: Zip (darwin-arm64)
        uses: montudor/action-zip@a8e75c9faefcd80fac3baf53ef40b9b119d5b702 # v1
        with:
          args: zip -qq kubelogin-darwin-arm64.zip bin/darwin_arm64/kubelogin

      - name: Zip (linux-amd64)
        uses: montudor/action-zip@a8e75c9faefcd80fac3baf53ef40b9b119d5b702 # v1
        with:
          args: zip -qq kubelogin-linux-amd64.zip bin/linux_amd64/kubelogin

      - name: Zip (linux-arm64)
        uses: montudor/action-zip@a8e75c9faefcd80fac3baf53ef40b9b119d5b702 # v1
        with:
          args: zip -qq kubelogin-linux-arm64.zip bin/linux_arm64/kubelogin

      - name: Zip (linux-armv7)
        uses: montudor/action-zip@a8e75c9faefcd80fac3baf53ef40b9b119d5b702 # v1
        with:
          args: zip -qq kubelogin-linux-armv7.zip bin/linux_armv7/kubelogin

      - name: Create sha256 Checksums
        run: |
          sha256sum kubelogin.zip > kubelogin.zip.sha256
          sha256sum kubelogin-win-amd64.zip > kubelogin-win-amd64.zip.sha256
          sha256sum kubelogin-win-arm64.zip > kubelogin-win-arm64.zip.sha256
          sha256sum kubelogin-darwin-amd64.zip > kubelogin-darwin-amd64.zip.sha256
          sha256sum kubelogin-darwin-arm64.zip > kubelogin-darwin-arm64.zip.sha256
          sha256sum kubelogin-linux-amd64.zip > kubelogin-linux-amd64.zip.sha256
          sha256sum kubelogin-linux-arm64.zip > kubelogin-linux-arm64.zip.sha256
          sha256sum kubelogin-linux-armv7.zip > kubelogin-linux-armv7.zip.sha256

      - name: Publish
        uses: skx/github-action-publish-binaries@44887b225ceca96efd8a912d39c09ad70312af31 # master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          args: kubelogin.zip kubelogin-win-amd64.zip kubelogin-win-arm64.zip kubelogin-darwin-amd64.zip kubelogin-darwin-arm64.zip kubelogin-linux-amd64.zip kubelogin-linux-arm64.zip kubelogin-linux-armv7.zip kubelogin.zip.sha256 kubelogin-win-amd64.zip.sha256 kubelogin-win-arm64.zip.sha256 kubelogin-darwin-amd64.zip.sha256 kubelogin-darwin-arm64.zip.sha256 kubelogin-linux-amd64.zip.sha256 kubelogin-linux-arm64.zip.sha256 kubelogin-linux-armv7.zip.sha256
          releaseId: ${{ needs.create-release.outputs.release_id }}
07070100000011000081A4000000000000000000000001687816E5000003BF000000000000000000000000000000000000003000000000kubelogin-0.2.10/.github/workflows/website.yamlname: generate github pages

on:
  push:
    branches:
      - main
    paths:
      - ".github/workflows/website.yaml"
      - "docs/**"

jobs:
  deploy:
    permissions:
      contents: write
      pages: write
      
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          submodules: true
          fetch-depth: 0

      - name: Set TOOLS_BIN_DIR and add to PATH
        run: |
          TOOLS_BIN_DIR="${HOME}/.cargo/bin"
          echo "TOOLS_BIN_DIR=${TOOLS_BIN_DIR}" >> ${GITHUB_ENV}
          echo "${TOOLS_BIN_DIR}" >> ${GITHUB_PATH}

      - name: Build
        run: make -C docs/book build

      - name: Deploy
        uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 # v3.9.3
        if: ${{ github.ref == 'refs/heads/main' }}
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./docs/book/book
07070100000012000081A4000000000000000000000001687816E50000014D000000000000000000000000000000000000001C00000000kubelogin-0.2.10/.gitignore# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
*.cov
bin
kubelogin

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

coverage.txt

# JetBrains IDE folder
.idea
07070100000013000081A4000000000000000000000001687816E500000202000000000000000000000000000000000000001F00000000kubelogin-0.2.10/.golangci.ymlrun:
  # default concurrency is a available CPU number
  concurrency: 4
  deadline: 10m
  tests: false

linters:
  disable-all: true
  enable:
    - errcheck
    - goconst
    - gocritic
    - goimports
    - gosec
    - govet
    - ineffassign
    - misspell
    - paralleltest
    - staticcheck
    - stylecheck
    - unused

linters-settings:
  gocritic:
    disabled-checks:
    - ifElseChain
  misspell:
    locale: US
  gosec:
    excludes:
    - G101
  goimports:
    local-prefixes: github.com/org/project
07070100000014000081A4000000000000000000000001687816E5000001A3000000000000000000000000000000000000002900000000kubelogin-0.2.10/.pre-commit-config.yamlrepos:
- repo: https://github.com/gitleaks/gitleaks
  rev: v8.16.3
  hooks:
  - id: gitleaks
- repo: https://github.com/golangci/golangci-lint
  rev: v1.52.2
  hooks:
  - id: golangci-lint
- repo: https://github.com/jumanjihouse/pre-commit-hooks
  rev: 3.0.0
  hooks:
  - id: shellcheck
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v4.4.0
  hooks:
  - id: end-of-file-fixer
  - id: trailing-whitespace
07070100000015000081A4000000000000000000000001687816E5000057B2000000000000000000000000000000000000001E00000000kubelogin-0.2.10/CHANGELOG.md# Change Log

## [0.2.10]

### What's Changed

* Add Docker Image Build and Publish Workflow by @Copilot in https://github.com/Azure/kubelogin/pull/680
* Fix Docker registry name case issue in GitHub Actions workflow by @Copilot in https://github.com/Azure/kubelogin/pull/682

### Maintenance

* Fix CVE-2025-22871 and CVE-2025-22868: Update Go version and security dependencies by @Copilot in https://github.com/Azure/kubelogin/pull/678

### New Contributors

* @Copilot made their first contribution in https://github.com/Azure/kubelogin/pull/678

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.2.9...v0.2.10

## [0.2.9]

### What's Changed

* added redirect-url to interactive mode by @weinong in https://github.com/Azure/kubelogin/pull/661
* added Interactive login hint by @weinong in https://github.com/Azure/kubelogin/pull/663
* Add caching support for PoP token acquisition by @JorgeDaboub in https://github.com/Azure/kubelogin/pull/662
* feat: update documentation by @jakangah in https://github.com/Azure/kubelogin/pull/669

### New Contributors

* @jakangah made their first contribution in https://github.com/Azure/kubelogin/pull/669

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.2.8...v0.2.9

## [0.2.8]

### Maintenance

* Bump github.com/golang-jwt/jwt/v4 from 4.5.1 to 4.5.2 by @dependabot in https://github.com/Azure/kubelogin/pull/648
* Bump golang.org/x/net from 0.36.0 to 0.38.0 by @dependabot in https://github.com/Azure/kubelogin/pull/651

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.2.7...v0.2.8

## [0.2.7]

### What's Changed

* fix missing prompt and increase default timeout to 60s by @weinong in https://github.com/Azure/kubelogin/pull/643
* ignore cache create failure by @weinong in https://github.com/Azure/kubelogin/pull/644
* fix missing build tag in --version by @weinong in https://github.com/Azure/kubelogin/pull/645

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.2.6...v0.2.7

## [0.2.6]

### What's Changed

* fixed the unneeded tenant id validation in azurecli login by @weinong in https://github.com/Azure/kubelogin/pull/637
* remove tenant id validation for azuredevops login by @weinong in https://github.com/Azure/kubelogin/pull/638

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.2.5...v0.2.6

## [0.2.5]

### What's Changed

* fixed a bug where server-id flag is always required by @weinong in https://github.com/Azure/kubelogin/pull/634

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.2.4...v0.2.5

## [0.2.4]

### What's Changed

* disable cgo for linux and windows by @weinong in https://github.com/Azure/kubelogin/pull/631

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.2.3...v0.2.4

## [0.2.3]

### What's Changed

* use tar to retain executable bit in released assets by @weinong in https://github.com/Azure/kubelogin/pull/628

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.2.2...v0.2.3

## [0.2.2]

### What's Changed

* fixed broken release assets by @weinong in https://github.com/Azure/kubelogin/pull/625

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.2.1...v0.2.2

## [0.2.1]

### What's Changed

* updated artifact actions by @weinong in https://github.com/Azure/kubelogin/pull/622

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.2.0...v0.2.1

## [0.2.0]

### What's Changed

* rewrote token implementation and added official cache support by @weinong in https://github.com/Azure/kubelogin/pull/608
  **This change includes breaking change so that the minor version is bumped**:
  - Previous caching implementation is removed. Now we are using caching provided by azidentity. This also means any credential flows not implemented by azidentity will not have any caching. Notably, interactive with pop, device code with legacy and ropc with pop will NOT have cache.
  - The binary is now built with CGO enabled to allow secure token caching on the host

### Maintenance

* Bump golang.org/x/net from 0.33.0 to 0.36.0 by @dependabot in https://github.com/Azure/kubelogin/pull/618
* added missing checkout to fix release by @weinong in https://github.com/Azure/kubelogin/pull/620

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.1.9...v0.2.0

## [0.1.9]

### What's Changed

* Add disable-instance-discovery option in interactive pop mode by @Aijing2333 in https://github.com/Azure/kubelogin/pull/593

### Maintenance

* Bump codecov/codecov-action from 3.1.5 to 5.1.2 by @dependabot in https://github.com/Azure/kubelogin/pull/583
* Bump mukunku/tag-exists-action from 1.1.0 to 1.6.0 by @dependabot in https://github.com/Azure/kubelogin/pull/405
* Bump go.uber.org/mock from 0.4.0 to 0.5.0 by @dependabot in https://github.com/Azure/kubelogin/pull/545
* chore: bump go to 1.23.7 by @bcho in https://github.com/Azure/kubelogin/pull/611

### New Contributors
* @Aijing2333 made their first contribution in https://github.com/Azure/kubelogin/pull/593

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.1.7...v0.1.9

## [0.1.7]

### What's Changed

* Improve shell completion for convert-config by @albers in https://github.com/Azure/kubelogin/pull/582
* Shell completion enhancements by @albers in https://github.com/Azure/kubelogin/pull/586
* Adding an option to disable instance discovery in AcquirePoPTokenConfidential by @bganapa in https://github.com/Azure/kubelogin/pull/595
* Add disable environment override option. by @dpersson in https://github.com/Azure/kubelogin/pull/594

### Maintenance

* chore: bump golang.org/x/net to v0.33.0 to mitigate CVE-2024-45338 by @bcho in https://github.com/Azure/kubelogin/pull/584
* address codeql issues by @weinong in https://github.com/Azure/kubelogin/pull/588
* Update website.yaml by @weinong in https://github.com/Azure/kubelogin/pull/589
* Fix install link for golangci-lint by @albers in https://github.com/Azure/kubelogin/pull/585
* use bingo to manage golangci-lint by @weinong in https://github.com/Azure/kubelogin/pull/590
* default codeql does not allow uploading 3rd party scanning result by @weinong in https://github.com/Azure/kubelogin/pull/591
* fixed the default target in makefile by @weinong in https://github.com/Azure/kubelogin/pull/601

### New Contributors

* @albers made their first contribution in https://github.com/Azure/kubelogin/pull/582
* @bganapa made their first contribution in https://github.com/Azure/kubelogin/pull/595
* @dpersson made their first contribution in https://github.com/Azure/kubelogin/pull/594

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.1.6...v0.1.7

## [0.1.6]

### Enhancements

* remove snap since it's unsupported by @weinong in https://github.com/Azure/kubelogin/pull/564
* Add x5c Header when Acquiring PoP Tokens by @JorgeDaboub in https://github.com/Azure/kubelogin/pull/568

### Maintenance

* Bump golang.org/x/crypto from 0.27.0 to 0.31.0 by @dependabot in https://github.com/Azure/kubelogin/pull/576

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.1.5...v0.1.6

## [0.1.5]

### Enhancements

* support of environment variable KUBECACHEDIR #500 by @jjournet in https://github.com/Azure/kubelogin/pull/501
* Use AZURE_CONFIG_DIR in kubelogin command example by @tspearconquest in https://github.com/Azure/kubelogin/pull/522
* fix: fix fallback to Git tag if VCS is unavailable by @maxbrunet in https://github.com/Azure/kubelogin/pull/530
* Expose MSAL PoP for Consistent CSP Integration by @JorgeDaboub in https://github.com/Azure/kubelogin/pull/542

### Maintenance

* Bump ossf/scorecard-action from 2.0.6 to 2.4.0 by @dependabot in https://github.com/Azure/kubelogin/pull/498
* Bump golang.org/x/crypto from 0.24.0 to 0.25.0 by @dependabot in https://github.com/Azure/kubelogin/pull/490
* Bump golang.org/x/crypto from 0.25.0 to 0.26.0 by @dependabot in https://github.com/Azure/kubelogin/pull/505
* Bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 by @dependabot in https://github.com/Azure/kubelogin/pull/543
* Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.6.0 to 1.8.0 by @dependabot in https://github.com/Azure/kubelogin/pull/534
* Preemptive fix for the breaking GH Action. by @Tatsinnit in https://github.com/Azure/kubelogin/pull/546

### New Contributors

* @jjournet made their first contribution in https://github.com/Azure/kubelogin/pull/501
* @tspearconquest made their first contribution in https://github.com/Azure/kubelogin/pull/522
* @maxbrunet made their first contribution in https://github.com/Azure/kubelogin/pull/530
* @JorgeDaboub made their first contribution in https://github.com/Azure/kubelogin/pull/542

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.1.4...v0.1.5

## [0.1.4]

### Maintenance

* Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.5.1 to 1.6.0 by @dependabot in https://github.com/Azure/kubelogin/pull/474
* feat: declare go version directive with patch version by @bcho in https://github.com/Azure/kubelogin/pull/476
* Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.11.1 to 1.12.0 by @dependabot in https://github.com/Azure/kubelogin/pull/478
* chore: upgrade go to v1.21.11 to fix CVE-2024-24790 by @strivedi-px in https://github.com/Azure/kubelogin/pull/485
* Bump k8s.io/klog/v2 from 2.110.1 to 2.130.1 by @dependabot in https://github.com/Azure/kubelogin/pull/483
* Bump github.com/spf13/cobra from 1.8.0 to 1.8.1 by @dependabot in https://github.com/Azure/kubelogin/pull/482
* Bump github.com/stretchr/testify from 1.8.4 to 1.9.0 by @dependabot in https://github.com/Azure/kubelogin/pull/444
* Bump gopkg.in/dnaeon/go-vcr.v3 from 3.1.2 to 3.2.0 by @dependabot in https://github.com/Azure/kubelogin/pull/459

### New Contributors

* @strivedi-px made their first contribution in https://github.com/Azure/kubelogin/pull/485

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.1.3...v0.1.4

## [0.1.3]

- Bump golang.org/x/net from 0.21.0 to 0.23.0 by @dependabot in https://github.com/Azure/kubelogin/pull/451

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.1.2...v0.1.3

## [0.1.2]

### Maintenance

- Bump google.golang.org/protobuf from 1.30.0 to 1.33.0 by @dependabot in https://github.com/Azure/kubelogin/pull/430
- Bump k8s.io/cli-runtime from 0.28.3 to 0.29.3 by @dependabot in https://github.com/Azure/kubelogin/pull/433
- fix: tidy go.mod and bump go version by @bcho in https://github.com/Azure/kubelogin/pull/448
- Bump golang.org/x/crypto from 0.18.0 to 0.22.0 by @dependabot in https://github.com/Azure/kubelogin/pull/445
- Bump github.com/google/uuid from 1.5.0 to 1.6.0 by @dependabot in https://github.com/Azure/kubelogin/pull/406
- Bump github.com/golang-jwt/jwt/v5 from 5.2.0 to 5.2.1 by @dependabot in https://github.com/Azure/kubelogin/pull/443

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.1.1...v0.1.2

## [0.1.1]

### Enhancements

- Adds Azure Developer CLI (azd) as a new login method by @wbreza in https://github.com/Azure/kubelogin/pull/398
- Add PoP token support for ROPC flow by @rharpavat in https://github.com/Azure/kubelogin/pull/412

### Maintenance

- Default branch is now main. by @Tatsinnit in https://github.com/Azure/kubelogin/pull/390
- Changes in correlation with new GH Action Permission Changes. by @Tatsinnit in https://github.com/Azure/kubelogin/pull/400
- Bump github.com/AzureAD/microsoft-authentication-library-for-go from 1.2.0 to 1.2.1 by @dependabot in https://github.com/Azure/kubelogin/pull/391
- Bump golang.org/x/crypto from 0.17.0 to 0.18.0 by @dependabot in https://github.com/Azure/kubelogin/pull/392
- [StepSecurity] Apply security best practices by @step-security-bot in https://github.com/Azure/kubelogin/pull/404

### New Contributors

- @wbreza made their first contribution in https://github.com/Azure/kubelogin/pull/398
- @step-security-bot made their first contribution in https://github.com/Azure/kubelogin/pull/404

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.1.0...v0.1.1

## [0.1.0]

### Enhancements

- [library usage] Move modules under `pkg` to `pkg/internal` by @bcho in https://github.com/Azure/kubelogin/pull/376
- [library usage] Update module version usages by @bcho in https://github.com/Azure/kubelogin/pull/377
- [library usage] Refine internal token types by @bcho in https://github.com/Azure/kubelogin/pull/379
- [library usage] Implement library token provider by @bcho in https://github.com/Azure/kubelogin/pull/380
- [library usage] fix: downgrade required go version to 1.20 by @bcho in https://github.com/Azure/kubelogin/pull/386

### Maintenance

- Bump github.com/spf13/cobra from 1.7.0 to 1.8.0 by @dependabot in https://github.com/Azure/kubelogin/pull/359
- Bump golang.org/x/crypto from 0.14.0 to 0.17.0 by @dependabot in https://github.com/Azure/kubelogin/pull/378
- Bump github.com/golang-jwt/jwt/v5 from 5.0.0 to 5.2.0 by @dependabot in https://github.com/Azure/kubelogin/pull/370
- Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.8.0 to 1.9.1 by @dependabot in https://github.com/Azure/kubelogin/pull/372
- Bump go.uber.org/mock from 0.3.0 to 0.4.0 by @dependabot in https://github.com/Azure/kubelogin/pull/385
- Bump github.com/google/uuid from 1.4.0 to 1.5.0 by @dependabot in https://github.com/Azure/kubelogin/pull/383

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.0.34...v0.1.0

## [0.0.34]

### Enhancements

* feat(timeout): Implement customizable timeout for Azure CLI token ret… by @Aricg in https://github.com/Azure/kubelogin/pull/362
* added github token support by @weinong in https://github.com/Azure/kubelogin/pull/366
* added armv7 support by @weinong in https://github.com/Azure/kubelogin/pull/367

### Maintenance

* bump golang to 1.21 by @weinong in https://github.com/Azure/kubelogin/pull/356
* Bump k8s.io/klog/v2 from 2.100.1 to 2.110.1 by @dependabot in https://github.com/Azure/kubelogin/pull/357
* Bump github.com/google/uuid from 1.3.1 to 1.4.0 by @dependabot in https://github.com/Azure/kubelogin/pull/355

## New Contributors
* @Aricg made their first contribution in https://github.com/Azure/kubelogin/pull/362

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.0.33...v0.0.34

## [0.0.33]

### Enhancements

- use the adal library for spn when --legacy is specified by @weinong in https://github.com/Azure/kubelogin/pull/338

### Maintenance

- Bump github.com/google/uuid from 1.3.0 to 1.3.1 by @dependabot in https://github.com/Azure/kubelogin/pull/334
- Add 1P client/server app IDs to docs by @rharpavat in https://github.com/Azure/kubelogin/pull/336
- Update install.md by @torreymicrosoft in https://github.com/Azure/kubelogin/pull/342
- Bump golang.org/x/net from 0.10.0 to 0.17.0 by @dependabot in https://github.com/Azure/kubelogin/pull/347
- Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.6.1 to 1.8.0 by @dependabot in https://github.com/Azure/kubelogin/pull/344
- Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.3.0 to 1.4.0 by @dependabot in https://github.com/Azure/kubelogin/pull/346
- Bump k8s.io/cli-runtime from 0.27.2 to 0.28.2 by @dependabot in https://github.com/Azure/kubelogin/pull/340
- Bump k8s.io/cli-runtime from 0.28.2 to 0.28.3 by @dependabot in https://github.com/Azure/kubelogin/pull/351
- Bump github.com/google/go-cmp from 0.5.9 to 0.6.0 by @dependabot in https://github.com/Azure/kubelogin/pull/349
- Bump github.com/stretchr/testify from 1.8.2 to 1.8.4 by @dependabot in https://github.com/Azure/kubelogin/pull/348

## New Contributors

- @torreymicrosoft made their first contribution in https://github.com/Azure/kubelogin/pull/342

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.0.32...v0.0.33

## [0.0.32]

### Enhancements

- Add PoP token support to interactive+spn get-token/convert-kubeconfig flows by @rharpavat in https://github.com/Azure/kubelogin/pull/319

### Maintenance

- Fixed typo in top header for convert-kubeconfig documentation by @byk0t in https://github.com/Azure/kubelogin/pull/323
- Bump golang.org/x/crypto from 0.11.0 to 0.12.0 by @dependabot in https://github.com/Azure/kubelogin/pull/315
- Bump k8s.io/apimachinery from 0.27.3 to 0.27.4 by @dependabot in https://github.com/Azure/kubelogin/pull/310

## New Contributors

- @byk0t made their first contribution in https://github.com/Azure/kubelogin/pull/323
- @rharpavat made their first contribution in https://github.com/Azure/kubelogin/pull/319

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.0.31...v0.0.32

## [0.0.31]

### Enhancements

- upgrade klog from v1 to v2 by @peterbom in https://github.com/Azure/kubelogin/pull/306

### Maintenance

- Bump k8s.io/apimachinery from 0.27.2 to 0.27.3 by @dependabot in https://github.com/Azure/kubelogin/pull/297
- Bump golang.org/x/crypto from 0.10.0 to 0.11.0 by @dependabot in https://github.com/Azure/kubelogin/pull/303
- Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.6.0 to 1.6.1 by @dependabot in https://github.com/Azure/kubelogin/pull/292
- Bump golang.org/x/crypto from 0.9.0 to 0.10.0 by @dependabot in https://github.com/Azure/kubelogin/pull/294

### Doc Update

- docs: Use asdf-plugins index instead of hard coded repo https://github.com/Azure/kubelogin/pull/298
- Add chocolatey installation instructions https://github.com/Azure/kubelogin/pull/299

### New Contributors

- @peterbom made their first contribution in https://github.com/Azure/kubelogin/pull/306
- @sechmann made their first contribution in https://github.com/Azure/kubelogin/pull/298
- @moredatapls made their first contribution in https://github.com/Azure/kubelogin/pull/299

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.0.30...v0.0.31

## [0.0.30]

### Enhancements

- added verbose logging in convert-kubeconfig by @weinong in https://github.com/Azure/kubelogin/pull/272
- Adding installHint field to kubeconfigs that have been converted to the exec format by @cirvine-MSFT in https://github.com/Azure/kubelogin/pull/282

### Maintenance

- Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.1.1 to 1.5.0 by @dependabot in https://github.com/Azure/kubelogin/pull/249
- Bump github.com/AzureAD/microsoft-authentication-library-for-go from 0.9.0 to 1.0.0 by @dependabot in https://github.com/Azure/kubelogin/pull/259
- Bump k8s.io/cli-runtime from 0.26.3 to 0.27.1 by @dependabot in https://github.com/Azure/kubelogin/pull/262
- Bump github.com/Azure/go-autorest/autorest from 0.11.28 to 0.11.29 by @dependabot in https://github.com/Azure/kubelogin/pull/273
- add unit tests for `manualtoken_test.go` by @khareyash05 in https://github.com/Azure/kubelogin/pull/268
- Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.5.0 to 1.6.0 by @dependabot in https://github.com/Azure/kubelogin/pull/274
- Bump golang.org/x/crypto from 0.8.0 to 0.9.0 by @dependabot in https://github.com/Azure/kubelogin/pull/277
- Bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.2.2 to 1.3.0 by @dependabot in https://github.com/Azure/kubelogin/pull/278
- Bump k8s.io/apimachinery from 0.27.1 to 0.27.2 by @dependabot in https://github.com/Azure/kubelogin/pull/283
- Bump k8s.io/cli-runtime from 0.27.1 to 0.27.2 by @dependabot in https://github.com/Azure/kubelogin/pull/285
- Azidentity migration for service principal token by @ekoehn in https://github.com/Azure/kubelogin/pull/287
- update go to address CVE by @weinong in https://github.com/Azure/kubelogin/pull/290

### Doc Update

- update doc for v0.0.29 by @weinong in https://github.com/Azure/kubelogin/pull/270

### New Contributors

- @khareyash05 made their first contribution in https://github.com/Azure/kubelogin/pull/268
- @ekoehn made their first contribution in https://github.com/Azure/kubelogin/pull/287

**Full Changelog**: https://github.com/Azure/kubelogin/compare/v0.0.29...v0.0.30

## [0.0.29]

### Enhancements

- add --context support in convert subcommand by @weinong in https://github.com/Azure/kubelogin/pull/260
- return error when specified context is not found by @weinong in https://github.com/Azure/kubelogin/pull/261
- add --azure-config-dir in convert-kubeconfig subcommand by @weinong in https://github.com/Azure/kubelogin/pull/263

### Maintenance

- Enable Code Cov for this repo. by @Tatsinnit in https://github.com/Azure/kubelogin/pull/229
- Bump golang.org/x/crypto from 0.6.0 to 0.7.0 by @dependabot in https://github.com/Azure/kubelogin/pull/230
- Bump k8s.io/client-go from 0.26.2 to 0.26.3 by @dependabot in https://github.com/Azure/kubelogin/pull/234
- Feature/addtests by @Tatsinnit in https://github.com/Azure/kubelogin/pull/238
- Bump k8s.io/cli-runtime from 0.26.2 to 0.26.3 by @dependabot in https://github.com/Azure/kubelogin/pull/237
- Bump github.com/spf13/cobra from 1.6.1 to 1.7.0 by @dependabot in https://github.com/Azure/kubelogin/pull/245
- Bump golang.org/x/crypto from 0.7.0 to 0.8.0 by @dependabot in https://github.com/Azure/kubelogin/pull/250
- Add codecov badge to this repo. by @Tatsinnit in https://github.com/Azure/kubelogin/pull/252
- Bump k8s.io/apimachinery from 0.26.3 to 0.27.1 by @dependabot in https://github.com/Azure/kubelogin/pull/257
- Bump k8s.io/client-go from 0.26.3 to 0.27.1 by @dependabot in https://github.com/Azure/kubelogin/pull/258
- Fix merge conflicts and breaking changes in PR 221 by @cirvine-MSFT in https://github.com/Azure/kubelogin/pull/264
- Fix merge conflicts in PR 232 updating adal from 0.9.22 to 0.9.23 by @cirvine-MSFT in https://github.com/Azure/kubelogin/pull/265

### Doc Update

- refactor windows install doc by @weinong in https://github.com/Azure/kubelogin/pull/233
- adding github pages by @weinong in https://github.com/Azure/kubelogin/pull/241
- added inline toc by @weinong in https://github.com/Azure/kubelogin/pull/244
- Document scoop installation option by @goostleek in https://github.com/Azure/kubelogin/pull/242
- revamp the website by @weinong in https://github.com/Azure/kubelogin/pull/246
- update readme and docs by @weinong in https://github.com/Azure/kubelogin/pull/247
- ignore docs and readme on some workflows by @weinong in https://github.com/Azure/kubelogin/pull/248
- Add reference to a context. by @Tatsinnit in https://github.com/Azure/kubelogin/pull/253
- How to install kubelogin with asdf tool manager by @daveneeley in https://github.com/Azure/kubelogin/pull/256
- Update devicecode.md by @madhurgupta03 in https://github.com/Azu
07070100000016000081A4000000000000000000000001687816E5000001C5000000000000000000000000000000000000002400000000kubelogin-0.2.10/CODE_OF_CONDUCT.md# Microsoft Open Source Code of Conduct

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).

Resources:

- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
07070100000017000081A4000000000000000000000001687816E500000253000000000000000000000000000000000000001C00000000kubelogin-0.2.10/Dockerfile# Dockerfile for kubelogin
# This Dockerfile copies a pre-built binary into a minimal scratch image.
# The binary should be built before running docker build using: make kubelogin
# 
# Usage:
#   make build-image                    # Build with latest tag
#   GIT_TAG=v1.0.0 make build-image   # Build with specific tag
#
FROM scratch

# Build arguments for multi-architecture support
ARG TARGETARCH=amd64

# Copy the pre-built binary from local build to /usr/local/bin
COPY bin/linux_${TARGETARCH}/kubelogin /usr/local/bin/kubelogin

# Set the entrypoint
ENTRYPOINT ["/usr/local/bin/kubelogin"]07070100000018000081A4000000000000000000000001687816E50000048A000000000000000000000000000000000000001900000000kubelogin-0.2.10/LICENSE    MIT License

    Copyright (c) Microsoft Corporation.

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE
07070100000019000081A4000000000000000000000001687816E50000072A000000000000000000000000000000000000001A00000000kubelogin-0.2.10/Makefile.DEFAULT_GOAL := all

include .bingo/Variables.mk

TARGET     := kubelogin
OS         := $(if $(GOOS),$(GOOS),$(shell go env GOOS))
ARCH       := $(if $(GOARCH),$(GOARCH),$(shell go env GOARCH))
GOARM      := $(if $(GOARM),$(GOARM),)
BIN         = bin/$(OS)_$(ARCH)$(if $(GOARM),v$(GOARM),)/$(TARGET)
ifeq ($(OS),windows)
  BIN = bin/$(OS)_$(ARCH)$(if $(GOARM),v$(GOARM),)/$(TARGET).exe
endif

GIT_TAG    := $(if $(GIT_TAG),$(GIT_TAG),)

LDFLAGS    := -X main.gitTag=$(GIT_TAG)

all: $(TARGET)

help:
	@echo "Available targets:"
	@echo "  all          - Build the kubelogin binary (default)"
	@echo "  $(TARGET)    - Build the kubelogin binary"
	@echo "  lint         - Run linting checks"
	@echo "  test         - Run tests (includes linting)"
	@echo "  clean        - Remove built binaries"
	@echo "  build-image  - Build Docker image with kubelogin binary"
	@echo ""
	@echo "Docker image build options:"
	@echo "  make build-image                    # Build with 'latest' tag"
	@echo "  GIT_TAG=v1.0.0 make build-image   # Build with specific tag"
	@echo ""
	@echo "Environment variables:"
	@echo "  GOOS         - Target OS (default: $(OS))"
	@echo "  GOARCH       - Target architecture (default: $(ARCH))"
	@echo "  GIT_TAG      - Git tag for version info and Docker tagging"

lint: $(GOLANGCI_LINT)
	$(GOLANGCI_LINT) run

test: lint
	go test -race -coverprofile=coverage.txt -covermode=atomic ./...

$(TARGET): clean
	CGO_ENABLED=$(if $(CGO_ENABLED),$(CGO_ENABLED),0) go build -o $(BIN) -ldflags "$(LDFLAGS)"

clean:
	-rm -f $(BIN)

# Docker image build target
IMAGE_NAME    := ghcr.io/azure/kubelogin
IMAGE_TAG     := $(if $(GIT_TAG),$(GIT_TAG),latest)

build-image: $(TARGET)
	docker build -t $(IMAGE_NAME):$(IMAGE_TAG) .
	@if [ "$(GIT_TAG)" != "" ]; then \
		docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(IMAGE_NAME):latest; \
	fi
0707010000001A000081A4000000000000000000000001687816E5000008B0000000000000000000000000000000000000001B00000000kubelogin-0.2.10/README.md# kubelogin

[![Go Report Card](https://goreportcard.com/badge/github.com/Azure/kubelogin)](https://goreportcard.com/report/github.com/Azure/kubelogin)
[![golangci-lint](https://github.com/Azure/kubelogin/actions/workflows/golangci-lint.yml/badge.svg)](https://github.com/Azure/kubelogin/actions/workflows/golangci-lint.yml)
[![Build on Push](https://github.com/Azure/kubelogin/actions/workflows/build.yml/badge.svg)](https://github.com/Azure/kubelogin/actions/workflows/build.yml)
[![Go Reference](https://pkg.go.dev/badge/github.com/Azure/kubelogin.svg)](https://pkg.go.dev/github.com/Azure/kubelogin)
[![codecov](https://codecov.io/gh/Azure/kubelogin/branch/main/graph/badge.svg?token=02PZRX59VM)](https://codecov.io/gh/Azure/kubelogin)

This is a [client-go credential (exec) plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins) implementing azure authentication. This plugin provides features that are not available in kubectl. It is supported on kubectl v1.11+

Check out [the official doc page](https://azure.github.io/kubelogin/index.html) for more details

## Installation

https://azure.github.io/kubelogin/install.html

## Quick Start

https://azure.github.io/kubelogin/quick-start.html

## Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit <https://cla.opensource.microsoft.com>.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
0707010000001B000081A4000000000000000000000001687816E500000B2C000000000000000000000000000000000000001D00000000kubelogin-0.2.10/SECURITY.md<!-- BEGIN MICROSOFT SECURITY.MD V0.0.4 BLOCK -->

## Security

Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).

If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.

## Reporting Security Issues

**Please do not report security vulnerabilities through public GitHub issues.**

Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).

If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).

You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 

Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:

  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
  * Full paths of source file(s) related to the manifestation of the issue
  * The location of the affected source code (tag/branch/commit or direct URL)
  * Any special configuration required to reproduce the issue
  * Step-by-step instructions to reproduce the issue
  * Proof-of-concept or exploit code (if possible)
  * Impact of the issue, including how an attacker might exploit the issue

This information will help us triage your report more quickly.

If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.

## Preferred Languages

We prefer all communications to be in English.

## Policy

Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).

<!-- END MICROSOFT SECURITY.MD BLOCK -->0707010000001C000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001600000000kubelogin-0.2.10/docs0707010000001D000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001B00000000kubelogin-0.2.10/docs/book0707010000001E000081A4000000000000000000000001687816E500000005000000000000000000000000000000000000002600000000kubelogin-0.2.10/docs/book/.gitignorebook
0707010000001F000081A4000000000000000000000001687816E5000002D1000000000000000000000000000000000000002400000000kubelogin-0.2.10/docs/book/MakefileTOOLS_BIN_DIR ?= $(PWD)/bin
# include tools bin dir in path so that mdbook-toc can be run by mdbook
PATH := ${PATH}:${TOOLS_BIN_DIR}
MDBOOK_VERSION ?= v0.4.27
# this version of mdbook-toc is built against mdbook 0.4.27
MDBOOK_TOC_VERSION ?= 0.11.2
MDBOOK_INSTALL := $(realpath ../../hack/install-mdbook.sh)
MDBOOK_TOC_INSTALL := $(realpath ../../hack/install-mdbook-toc.sh)

MDBOOK := $(TOOLS_BIN_DIR)/mdbook
$(MDBOOK):
	$(MDBOOK_INSTALL) ${MDBOOK_VERSION} ${TOOLS_BIN_DIR}

MDBOOK_TOC := $(TOOLS_BIN_DIR)/mdbook-toc
$(MDBOOK_TOC):
	$(MDBOOK_TOC_INSTALL) ${MDBOOK_TOC_VERSION} ${TOOLS_BIN_DIR}

DEPS := $(MDBOOK) $(MDBOOK_TOC)

.PHONY: build
build: $(DEPS)
	$(MDBOOK) build

.PHONY: serve
serve: $(DEPS)
	$(MDBOOK) serve
07070100000020000081A4000000000000000000000001687816E50000014D000000000000000000000000000000000000002500000000kubelogin-0.2.10/docs/book/book.toml[book]
authors = ["Weinong Wang"]
language = "en"
multilingual = false
src = "src"
title = "Azure Kubelogin"
description = "A Kubernetes credential (exec) plugin implementing azure authentication"

[preprocessor.toc]
command = "mdbook-toc"

[output.html]
curly-quotes = true
git-repository-url = "https://github.com/Azure/kubelogin"
07070100000021000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001F00000000kubelogin-0.2.10/docs/book/src07070100000022000081A4000000000000000000000001687816E500000444000000000000000000000000000000000000002900000000kubelogin-0.2.10/docs/book/src/README.md# Introduction

`kubelogin` is a [client-go credential (exec) plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins) implementing azure authentication. This plugin provides features that are not available in kubectl. It is supported on kubectl v1.11+

## Features

- [interactive device code login](./concepts/login-modes/devicecode.md)
- [interactive web browser login](./concepts/login-modes/interactive.md)
- [non-interactive service principal login](./concepts/login-modes/sp.md)
- [non-interactive user principal login](./concepts/login-modes/ropc.md) using [Resource owner login flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc)
- [non-interactive managed service identity login](./concepts/login-modes/msi.md)
- [non-interactive Azure CLI token login (AKS only)](./concepts/login-modes/azurecli.md)
- [non-interactive Azure Developer CLI token login (AKS only)](./concepts/login-modes/azd.md)
- [non-interactive workload identity login](./concepts/login-modes/workloadidentity.md)
07070100000023000081A4000000000000000000000001687816E5000005EB000000000000000000000000000000000000002A00000000kubelogin-0.2.10/docs/book/src/SUMMARY.md# Summary

- [Introduction](./README.md)
- [Installation](./install.md)
- [Quick Start](./quick-start.md)
- [Concepts](./concepts.md)
  - [Exec Plugin](./concepts/exec-plugin.md)
  - [Login Modes](./concepts/login-modes.md)
    - [Device Code](./concepts/login-modes/devicecode.md)
    - [Azure CLI](./concepts/login-modes/azurecli.md)
    - [Azure Developer CLI](./concepts/login-modes/azd.md)
    - [Web Browser Interactive](./concepts/login-modes/interactive.md)
    - [Service Principal](./concepts/login-modes/sp.md)
    - [Managed Service Identity](./concepts/login-modes/msi.md)
    - [Workload Identity](./concepts/login-modes/workloadidentity.md)
    - [Resource Owner Password Credential](./concepts/login-modes/ropc.md)
  - [Using kubelogin with AKS](./concepts/aks.md)
  - [Using kubelogin to get Proof-of-Possession (PoP) tokens for Azure Arc](./concepts/azure-arc.md)
- [Command-Line Tool](./cli-reference.md)
  - [convert-kubeconfig](./cli/convert-kubeconfig.md)
  - [get-token](./cli/get-token.md)
  - [remove-cache-dir](./cli/remove-cache-dir.md)
- [Topics](./topics.md)
  - [Using in different environments](./topics/environments.md)
  - [Using Service Principal](./topics/sp.md)
  - [Setup k8s OIDC Provider using Azure AD](./topics/k8s-oidc-aad.md)
  - [Using kubelogin in Jenkins](./topics/jenkins.md)
- [Known Issues](./known-issues.md)
- [Development](./development.md)
  - [Releasing](./development/releasing.md)
- [Contributing](./contributing.md)
- [Code of Conduct](./code-of-conduct.md)
07070100000024000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002300000000kubelogin-0.2.10/docs/book/src/cli07070100000025000081A4000000000000000000000001687816E500000620000000000000000000000000000000000000003000000000kubelogin-0.2.10/docs/book/src/cli-reference.md# Command Line Tool

`kubelogin` command-line tool has following subcommands:

```sh
kubelogin -h
login to azure active directory and populate kubeconfig with AAD tokens

Usage:
  kubelogin [flags]
  kubelogin [command]

Available Commands:
  completion         Generate the autocompletion script for the specified shell
  convert-kubeconfig convert kubeconfig to use exec auth module
  get-token          get AAD token
  help               Help about any command
  remove-cache-dir   Remove all cached authentication record from filesystem

Flags:
  -h, --help          help for kubelogin
      --logtostderr   log to standard error instead of files (default true)
  -v, --v Level       number for the log level verbosity
      --version       version for kubelogin

Use "kubelogin [command] --help" for more information about a command.

```

Following sections provide in-depth information on these subcommands:

* [`kubelogin convert-kubeconfig`](./cli/convert-kubeconfig.md) - converts the kubeconfig to different login mode
* [`kubelogin get-token`](./cli/get-token.md) - gets the Azure AD token based on configured login mode. This subcommand is typically used in kubeconfig via [exec plugin](./concepts/exec-plugin.md) and is invoked by kubectl or any command-line tool, such as helm, implementing exec plugin.
* [`kubelogin remove-cache-dir`](./cli/remove-cache-dir.md) - remove all cached authentication record from filesystem.
* [DEPRECATED] [`kubelogin remove-tokens`](./cli/remove-cache-dir.md) - remove all cached authentication record from filesystem.

07070100000026000081A4000000000000000000000001687816E500001208000000000000000000000000000000000000003900000000kubelogin-0.2.10/docs/book/src/cli/convert-kubeconfig.md# convert-kubeconfig

This subcommand converts kubeconfig to [Exec plugin](../concepts/exec-plugin.md) using `kubelogin get-token` with specified [login mode](../concepts/login-modes.md).

Note that when `--context` is specified, only the matching kubeconfig context will be converted. Otherwise, every kubeconfig context that uses azure auth or Exec plugin will be converted.

## Usage

```sh
kubelogin convert-kubeconfig -h
convert kubeconfig to use exec auth module

Usage:
  kubelogin convert-kubeconfig [flags]

Flags:
      --authority-host string                Workload Identity authority host. It may be specified in AZURE_AUTHORITY_HOST environment variable
      --azure-config-dir string              Azure CLI config path
      --cache-dir string                     directory to cache authentication record (default "/home/weinongw/.kube/cache/kubelogin/")
      --client-certificate string            AAD client cert in pfx. Used in spn login. It may be specified in AAD_SERVICE_PRINCIPAL_CLIENT_CERTIFICATE or AZURE_CLIENT_CERTIFICATE_PATH environment variable
      --client-certificate-password string   Password for AAD client cert. Used in spn login. It may be specified in AAD_SERVICE_PRINCIPAL_CLIENT_CERTIFICATE_PASSWORD or AZURE_CLIENT_CERTIFICATE_PASSWORD environment variable
      --client-id string                     AAD client application ID. It may be specified in AAD_SERVICE_PRINCIPAL_CLIENT_ID or AZURE_CLIENT_ID environment variable
      --client-secret string                 AAD client application secret. Used in spn login. It may be specified in AAD_SERVICE_PRINCIPAL_CLIENT_SECRET or AZURE_CLIENT_SECRET environment variable
      --context string                       The name of the kubeconfig context to use
      --disable-environment-override         Enable or disable the use of env-variables. Default false
      --disable-instance-discovery           set to true to disable instance discovery in environments with their own simple Identity Provider (not AAD) that do not have instance metadata discovery endpoint. Default false
  -e, --environment string                   Azure environment name (default "AzurePublicCloud")
      --federated-token-file string          Workload Identity federated token file. It may be specified in AZURE_FEDERATED_TOKEN_FILE environment variable
  -h, --help                                 help for convert-kubeconfig
      --identity-resource-id string          Managed Identity resource id.
      --kubeconfig string                    Path to the kubeconfig file to use for CLI requests.
      --legacy                               set to true to get token with 'spn:' prefix in audience claim
  -l, --login string                         Login method. Supported methods: devicecode, interactive, spn, ropc, msi, azurecli, azd, workloadidentity. It may be specified in AAD_LOGIN_METHOD environment variable (default "devicecode")
      --login-hint string                    The login hint to pre-fill the username in the interactive login flow.
      --password string                      password for ropc login flow. It may be specified in AAD_USER_PRINCIPAL_PASSWORD or AZURE_PASSWORD environment variable
      --pop-claims key=val,key2=val2         contains a comma-separated list of claims to attach to the pop token in the format key=val,key2=val2. At minimum, specify the ARM ID of the cluster as `u=ARM_ID`
      --pop-enabled                          set to true to use a PoP token for authentication or false to use a regular bearer token
      --redirect-url string                  The URL Microsoft Entra ID will redirect to with the access token. This is only used for interactive login. This is an optional parameter.
      --server-id string                     AAD server application ID
  -t, --tenant-id string                     AAD tenant ID. It may be specified in AZURE_TENANT_ID environment variable
      --timeout duration                     Timeout duration for Azure CLI token requests. It may be specified in AZURE_CLI_TIMEOUT environment variable (default 30s)
      --use-azurerm-env-vars                 Use environment variable names of Terraform Azure Provider (ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_CLIENT_CERTIFICATE_PATH, ARM_CLIENT_CERTIFICATE_PASSWORD, ARM_TENANT_ID)
      --username string                      user name for ropc login flow. It may be specified in AAD_USER_PRINCIPAL_NAME or AZURE_USERNAME environment variable

Global Flags:
      --logtostderr   log to standard error instead of files (default true)
  -v, --v Level       number for the log level verbosity
```
07070100000027000081A4000000000000000000000001687816E500001E3C000000000000000000000000000000000000003000000000kubelogin-0.2.10/docs/book/src/cli/get-token.md# get-token

This subcommand uses specified [login mode](../concepts/login-modes.md) to authenticate with Azure AD and return the access token to standard out.

## Usage

```sh
kubelogin get-token -h
get AAD token

Usage:
  kubelogin get-token [flags]

Flags:
      --authority-host string                Workload Identity authority host. It may be specified in AZURE_AUTHORITY_HOST environment variable
      --cache-dir string                     directory to cache authentication record (default "/home/weinongw/.kube/cache/kubelogin/")
      --client-certificate string            AAD client cert in pfx. Used in spn login. It may be specified in AAD_SERVICE_PRINCIPAL_CLIENT_CERTIFICATE or AZURE_CLIENT_CERTIFICATE_PATH environment variable
      --client-certificate-password string   Password for AAD client cert. Used in spn login. It may be specified in AAD_SERVICE_PRINCIPAL_CLIENT_CERTIFICATE_PASSWORD or AZURE_CLIENT_CERTIFICATE_PASSWORD environment variable
      --client-id string                     AAD client application ID. It may be specified in AAD_SERVICE_PRINCIPAL_CLIENT_ID or AZURE_CLIENT_ID environment variable
      --client-secret string                 AAD client application secret. Used in spn login. It may be specified in AAD_SERVICE_PRINCIPAL_CLIENT_SECRET or AZURE_CLIENT_SECRET environment variable
      --disable-environment-override         Enable or disable the use of env-variables. Default false
      --disable-instance-discovery           set to true to disable instance discovery in environments with their own simple Identity Provider (not AAD) that do not have instance metadata discovery endpoint. Default false
  -e, --environment string                   Azure environment name (default "AzurePublicCloud")
      --federated-token-file string          Workload Identity federated token file. It may be specified in AZURE_FEDERATED_TOKEN_FILE environment variable
  -h, --help                                 help for get-token
      --identity-resource-id string          Managed Identity resource id.
      --legacy                               set to true to get token with 'spn:' prefix in audience claim
  -l, --login string                         Login method. Supported methods: devicecode, interactive, spn, ropc, msi, azurecli, azd, workloadidentity. It may be specified in AAD_LOGIN_METHOD environment variable (default "devicecode")
      --login-hint string                    The login hint to pre-fill the username in the interactive login flow.
      --password string                      password for ropc login flow. It may be specified in AAD_USER_PRINCIPAL_PASSWORD or AZURE_PASSWORD environment variable
      --pop-claims key=val,key2=val2         contains a comma-separated list of claims to attach to the pop token in the format key=val,key2=val2. At minimum, specify the ARM ID of the cluster as `u=ARM_ID`
      --pop-enabled                          set to true to use a PoP token for authentication or false to use a regular bearer token
      --redirect-url string                  The URL Microsoft Entra ID will redirect to with the access token. This is only used for interactive login. This is an optional parameter.
      --server-id string                     AAD server application ID
  -t, --tenant-id string                     AAD tenant ID. It may be specified in AZURE_TENANT_ID environment variable
      --timeout duration                     Timeout duration for Azure CLI token requests. It may be specified in AZURE_CLI_TIMEOUT environment variable (default 30s)
      --use-azurerm-env-vars                 Use environment variable names of Terraform Azure Provider (ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_CLIENT_CERTIFICATE_PATH, ARM_CLIENT_CERTIFICATE_PASSWORD, ARM_TENANT_ID)
      --username string                      user name for ropc login flow. It may be specified in AAD_USER_PRINCIPAL_NAME or AZURE_USERNAME environment variable

Global Flags:
      --logtostderr   log to standard error instead of files (default true)
  -v, --v Level       number for the log level verbosity
```

## Exec Plugin Examples

> cluster info including cluster CA and FQDN are omitted in below examples

### Device Code Flow (default)

```yaml
kind: Config
preferences: {}
users:
  - name: user-name
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        command: kubelogin
        args:
          - get-token
          - --environment
          - AzurePublicCloud
          - --server-id
          - <AAD server app ID>
          - --client-id
          - <AAD client app ID>
          - --tenant-id
          - <AAD tenant ID>
```
### web browser Flow (default)

```yaml
kind: Config
preferences: {}
users:
  - name: user-name
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        args:
        - get-token
        - --login
        - interactive
        - --server-id
        - <AAD server app ID>
        - --client-id
        - <AAD client app ID>
        - --tenant-id
        - <AAD tenant ID>
        - --environment
        - AzurePublicCloud
        command: kubelogin
```

### Spn login with secret

```yaml
kind: Config
preferences: {}
users:
  - name: demouser
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        args:
          - get-token
          - --environment
          - AzurePublicCloud
          - --server-id
          - <AAD server app ID>
          - --client-id
          - <AAD client app ID>
          - --client-secret
          - <client_secret>
          - --tenant-id
          - <AAD tenant ID>
          - --login
          - spn
        command: kubelogin
        env: null
```

### Spn login with pfx certificate

```yaml
kind: Config
preferences: {}
users:
  - name: demouser
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        args:
          - get-token
          - --environment
          - AzurePublicCloud
          - --server-id
          - <AAD server app ID>
          - --client-id
          - <AAD client app ID>
          - --client-certificate
          - <client_certificate_path>
          - --tenant-id
          - <AAD tenant ID>
          - --login
          - spn
        command: kubelogin
        env: null
```

### Managed Service Identity

```yaml
kind: Config
preferences: {}
users:
  - name: user-name
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        command: kubelogin
        args:
          - get-token
          - --server-id
          - <AAD server app ID>
          - --login
          - msi
```

### Managed Service Identity with specific client ID

```yaml
kind: Config
preferences: {}
users:
  - name: user-name
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        command: kubelogin
        args:
          - get-token
          - --server-id
          - <AAD server app ID>
          - --client-id
          - <MSI app ID>
          - --login
          - msi
```

### Azure CLI token login

```yaml
kind: Config
preferences: {}
users:
  - name: demouser
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        args:
          - get-token
          - --server-id
          - <AAD server app ID>
          - --login
          - azurecli
        command: kubelogin
        env: null
```

### Workload Identity

```yaml
kind: Config
preferences: {}
users:
  - name: demouser
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        args:
          - get-token
          - --server-id
          - <AAD server app ID>
          - --login
          - workloadidentity
        command: kubelogin
        env: null
```
07070100000028000081A4000000000000000000000001687816E500000296000000000000000000000000000000000000003700000000kubelogin-0.2.10/docs/book/src/cli/remove-cache-dir.md# remove-cache-dir

This subcommand removes the cached access/refresh token from filesystem. Note that only `devicelogin`, `interactive`, and `ropc` login modes will cache the token.

## Usage

```sh
kubelogin remove-cache-dir -h
Remove all cached authentication record from filesystem

Usage:
  kubelogin remove-cache-dir [flags]

Flags:
      --cache-dir string   directory to cache authentication record (default "/home/weinongw/.kube/cache/kubelogin/")
  -h, --help               help for remove-cache-dir

Global Flags:
      --logtostderr   log to standard error instead of files (default true)
  -v, --v Level       number for the log level verbosity
```
07070100000029000081A4000000000000000000000001687816E5000001C5000000000000000000000000000000000000003200000000kubelogin-0.2.10/docs/book/src/code-of-conduct.md# Microsoft Open Source Code of Conduct

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).

Resources:

- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
0707010000002A000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002800000000kubelogin-0.2.10/docs/book/src/concepts0707010000002B000081A4000000000000000000000001687816E50000006F000000000000000000000000000000000000002B00000000kubelogin-0.2.10/docs/book/src/concepts.md# Concepts

This section documents the key concepts that will be used throughout the `kubelogin` command-line.
0707010000002C000081A4000000000000000000000001687816E500000337000000000000000000000000000000000000002F00000000kubelogin-0.2.10/docs/book/src/concepts/aks.md# Using kubelogin with AKS

AKS uses a pair of first party Azure AD applications. These application IDs are the same in all environments.

## Azure Kubernetes Service AAD Server

applicationID: 6dae42f8-4368-4678-94ff-3960e28e3630

This is the application used by the server side. The access token accessing AKS clusters need to be issued for this app.
In most of `kubelogin` [login modes](./login-modes.md), `--server-id` is required parameter in `kubelogin get-token`.

## Azure Kubernetes Service AAD Client

applicationID: 80faf920-1908-4b52-b5ef-a8e7bedfc67a

This is a public client application used by `kubelogin` to perform login on behalf of the user. 
It's used in [device code](./login-modes/devicecode.md), [web browser interactive](./login-modes/interactive.md), and [ropc](./login-modes/ropc.md) login modes.
0707010000002D000081A4000000000000000000000001687816E500000667000000000000000000000000000000000000003500000000kubelogin-0.2.10/docs/book/src/concepts/azure-arc.md# Using kubelogin with Azure Arc

kubelogin can be used to authenticate with Azure Arc-enabled clusters by requesting a [proof-of-possession (PoP) token](https://learn.microsoft.com/en-us/entra/msal/dotnet/advanced/proof-of-possession-tokens). This can be done by providing both of the following flags together:

1. `--pop-enabled`: indicates that `kubelogin` should request a PoP token instead of a regular bearer token
2. `--pop-claims`: is a comma-separated list of `key=value` claims to include in the PoP token. At minimum, this must include the u-claim as `u=ARM_ID_OF_CLUSTER`, which specifies the host that the requested token should allow access on.

These flags can be provided to either `kubelogin get-token` directly to get a PoP token, or to `kubelogin convert-kubeconfig` for `kubectl` to request the token internally. 

PoP token requests only work with `interactive` and `spn` login modes; these flags will be ignored if provided for other login modes.

## AAD Server App

```
applicationID: 6256c85f-0aad-4d50-b960-e6e9b21efe35
```

This is the application used by the server side. The access token needs to be issued for this app to access a 1P Arc-enabled cluster.

This server app ID is a required parameter for [`web browser interactive`](./login-modes/interactive.md) login mode supporting PoP token authentication.

## AAD Client App

```
applicationID: 3f4439ff-e698-4d6d-84fe-09c9d574f06b
```

This is a 1P client application used by `kubelogin` to perform login on behalf of the user. It should be used for [`web browser interactive`](./login-modes/interactive.md) login mode when using PoP token authentication.
0707010000002E000081A4000000000000000000000001687816E50000050B000000000000000000000000000000000000003700000000kubelogin-0.2.10/docs/book/src/concepts/exec-plugin.md# Exec Plugin

[Exec plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins) 
is one of Kubernetes authentication strategies which allows `kubectl` to execute an external command to receive user credentials to send to api-server.
Since Kubernetes 1.26, [the default azure auth plugin is removed from `client-go` and `kubectl`](https://github.com/kubernetes/kubernetes/blob/ad18954259eae3db51bac2274ed4ca7304b923c4/CHANGELOG/CHANGELOG-1.26.md).

To interact with an Azure AD enabled Kubernetes cluster, Exec plugin using `kubelogin` will be required.

A kubeconfig using exec plugin will look somewhat like:

```yaml
kind: Config
preferences: {}
users:
  - name: user-name
    user:
      exec:
        apiVersion: client.authentication.k8s.io/v1beta1
        command: kubelogin
        args:
          - get-token
          - --environment
          - AzurePublicCloud
          - --server-id
          - <AAD server app ID>
          - --client-id
          - <AAD client app ID>
          - --tenant-id
          - <AAD tenant ID>
```

When using `kubelogin` in Exec plugin, the kubeconfig tells `kubectl` to execute `kubelogin get-token` subcommand to perform various Azure AD [login modes](./login-modes.md) to get the access token.
0707010000002F000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000003400000000kubelogin-0.2.10/docs/book/src/concepts/login-modes07070100000030000081A4000000000000000000000001687816E50000074A000000000000000000000000000000000000003700000000kubelogin-0.2.10/docs/book/src/concepts/login-modes.md# Login Modes

Most of the interaction with `kubelogin` is around `convert-kubeconfig` subcommand 
which uses the input kubeconfig specified in `--kubeconfig` or `KUBECONFIG` environment variable 
to convert to the final kubeconfig in [exec format](./concepts/exec-plugin.md) based on specified login mode.

In this section, the login modes will be explained in details.

## How Login Works

The login modes that `kubelogin` implements are [AAD OAuth 2.0 token grant flows](https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow).
Throughout `kubelogin` subcommands, you will see below common flags. In general, these flags are already setup when you get the kubeconfig from AKS.

- `--tenant-id`: [Azure AD tenant ID](https://learn.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-how-to-find-tenant)
- `--client-id`: the application ID of the [public client application](https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-client-applications).
This client app is only used in [device code](./login-modes/devicecode.md), [web browser interactive](./login-modes/interactive.md), and [ropc](./login-modes/ropc.md) login modes.
- `--server-id`: the application ID of the [web app, or resource server](https://learn.microsoft.com/en-us/azure/active-directory/fundamentals/auth-oauth2). 
The token should be issued to this resource.

## References

* https://learn.microsoft.com/en-us/azure/active-directory/fundamentals/auth-oauth2
* https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
* https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
* https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
* https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc
07070100000031000081A4000000000000000000000001687816E500000280000000000000000000000000000000000000003B00000000kubelogin-0.2.10/docs/book/src/concepts/login-modes/azd.md# Azure Developer CLI (azd)

This login mode uses the already logged-in context performed by Azure Developer CLI to get the access token.
The token will be issued in the same Azure AD tenant as in `azd auth login`.

`kubelogin` will not cache any token since it's already managed by Azure Developer CLI.

> ### NOTE
>
> This login mode only works with managed AAD in AKS.

## Usage Examples

```sh
azd auth login

export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l azd

kubectl get nodes
```

## References

- https://learn.microsoft.com/azure/developer/azure-developer-cli/overview
- https://github.com/azure/azure-dev
07070100000032000081A4000000000000000000000001687816E500000405000000000000000000000000000000000000004000000000kubelogin-0.2.10/docs/book/src/concepts/login-modes/azurecli.md# Azure CLI

This login mode uses the already logged-in context performed by Azure CLI to get the [access token](https://docs.microsoft.com/en-us/cli/azure/account?view=azure-cli-latest#az_account_get_access_token).
The token will be issued in the same Azure AD tenant as in `az login`.

`kubelogin` will not cache any token since it's already managed by Azure CLI.

> ### NOTE
>
> This login mode only works with managed AAD in AKS.

## Usage Examples

```sh
az login

export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l azurecli

kubectl get nodes
```

When Azure CLI's config directory is outside the `${HOME}` directory, `--azure-config-dir` should be specified in `convert-kubeconfig` subcommand. It will generate the kubeconfig with environment variable configured. The same thing can also be achieved by setting environment variable `AZURE_CONFIG_DIR` to this directory while running `kubectl` command.

## References

- https://learn.microsoft.com/en-us/cli/azure/
- https://github.com/Azure/azure-cli
07070100000033000081A4000000000000000000000001687816E5000004F5000000000000000000000000000000000000004200000000kubelogin-0.2.10/docs/book/src/concepts/login-modes/devicecode.md# Device Code

This is the default login mode in `convert-kubeconfig` subcommand. So `-l devicecode` is optional. This login will prompt the device code for user to login on a browser. 

Before `kubelogin` and [Exec plugin](./concepts/exec-plugin.md) were introduced, the azure authentication mode in `kubectl` supports device code flow only. 
It uses an old library that produces the token with `audience` claim that has `spn:` prefix 
which is not compatible with AKS Managed AAD using On-Behalf-Of mode ([Issue86410](https://github.com/kubernetes/kubernetes/issues/86410)).
So when running `convert-kubeconfig` subcommand, `kubelogin` will remove the `spn:` prefix in `audience` claim.
If it's desired to keep the old behavior, add `--legacy`. 

If you are using kubeconfig from AKS Legacy AAD (AADv1) clusters, `kubelogin` will automatically add `--legacy` flag.

## Usage Examples

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig

kubectl get nodes

```

## Restrictions

- Device code login mode doesn't work when Conditional Access policy is configured on AAD tenant. Use [web browser interactive mode](./interactive.md) instead.


## References

- https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code
07070100000034000081A4000000000000000000000001687816E5000004DF000000000000000000000000000000000000004300000000kubelogin-0.2.10/docs/book/src/concepts/login-modes/interactive.md# Web Browser Interactive

This login mode will automatically open a browser to login the user. 
Once authenticated, the browser will redirect back to a local web server with access token.
The redirect URL can be set via `--redirect-url`.
This login mode complies with Conditional Access policy.

## Usage Examples

### Bearer token with interactive flow

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l interactive

kubectl get nodes
```

### Specifying Redirect URL

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l interactive --redirect-url http://localhost:8080

kubectl get nodes
```

### Specifying login user hint

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l interactive --login-hint user@example.com

kubectl get nodes
```


### Proof-of-possession (PoP) token with interactive flow

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l interactive --pop-enabled --pop-claims "u=/ARM/ID/OF/CLUSTER"

kubectl get nodes
```

### Clearing the cache

```sh
kubelogin remove-cache-dir
```

## References

- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.interactivebrowsercredential?view=azure-python
07070100000035000081A4000000000000000000000001687816E5000002F9000000000000000000000000000000000000003B00000000kubelogin-0.2.10/docs/book/src/concepts/login-modes/msi.md# Managed Service Identity

This login mode should be used in an environment where 
[Managed Service Identity](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) 
is available such as Azure Virtual Machine, Azure Virtual Machine ScaleSet, Cloud Shell, Azure Container Instance, and Azure App Service.

The token will not be cached on the filesystem.

## Usage Examples

### Using default Managed Service Identity

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l msi

kubectl get nodes
```

### Using Managed Service Identity with specific identity

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l msi --client-id <msi-client-id>

kubectl get nodes
```
07070100000036000081A4000000000000000000000001687816E5000003E1000000000000000000000000000000000000003C00000000kubelogin-0.2.10/docs/book/src/concepts/login-modes/ropc.md# Resource Owner Password Credential (ropc)

> ### Warning: 
> [Microsoft recommends you do not use the ROPC flow](https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc)

> ### Note: 
> ROPC is not supported in hybrid identity federation scenarios (for example, Azure AD and ADFS used to authenticate on-premises accounts). If users are redirected to an on-premises identity providers, Azure AD is not able to test the username and password against that identity provider. Pass-through authentication is supported with ROPC, however.
> It also does not work when MFA policy is enabled
> Personal accounts that are invited to an Azure AD tenant can't use ROPC

## Usage Examples

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l ropc

export AAD_USER_PRINCIPAL_NAME=foo@bar.com
export AAD_USER_PRINCIPAL_PASSWORD=<password>

kubectl get nodes
```

## Reference

https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
07070100000037000081A4000000000000000000000001687816E5000008A5000000000000000000000000000000000000003A00000000kubelogin-0.2.10/docs/book/src/concepts/login-modes/sp.md# Service Principal

This login mode uses the service principal to login. The credential may be provided via environment variables or flag.
The supported credentials are password and pfx client certificate.

The token will not be cached on the filesystem.

## Usage Examples

### Client secret in environment variable

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l spn

export AAD_SERVICE_PRINCIPAL_CLIENT_ID=<spn client id>
export AAD_SERVICE_PRINCIPAL_CLIENT_SECRET=<spn secret>

kubectl get nodes
```

### Client secret in environment variable

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l spn

export AZURE_CLIENT_ID=<spn client id>
export AZURE_CLIENT_SECRET=<spn secret>

kubectl get nodes
```

### Client secret in command-line flag

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l spn --client-id <spn client id> --client-secret <spn client secret>

kubectl get nodes
```

> ### Warning
> this will leave the secret in the kubeconfig

### Client certificate

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l spn

export AAD_SERVICE_PRINCIPAL_CLIENT_ID=<spn client id>
export AAD_SERVICE_PRINCIPAL_CLIENT_CERTIFICATE=/path/to/cert.pfx
export AAD_SERVICE_PRINCIPAL_CLIENT_CERTIFICATE_PASSWORD=<pfx password>

kubectl get nodes
```

### Client certificate

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l spn

export AZURE_CLIENT_ID=<spn client id>
export AZURE_CLIENT_CERTIFICATE_PATH=/path/to/cert.pfx
export AZURE_CLIENT_CERTIFICATE_PASSWORD=<pfx password>

kubectl get nodes
```

### Proof-of-possession (PoP) token with client secret from environment variables
```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l spn --pop-enabled --pop-claims "u=/ARM/ID/OF/CLUSTER"

export AAD_SERVICE_PRINCIPAL_CLIENT_ID=<spn client id>
export AAD_SERVICE_PRINCIPAL_CLIENT_SECRET=<spn secret>

kubectl get nodes
```

## Restrictions

- on AKS, it will only work with managed AAD
- the service principal can be member of [maximum 200 AAD groups](https://learn.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-fed-group-claims) 
07070100000038000081A4000000000000000000000001687816E5000004F0000000000000000000000000000000000000004800000000kubelogin-0.2.10/docs/book/src/concepts/login-modes/workloadidentity.md# Workload Identity

This login mode uses [Azure AD federated identity credentials](https://docs.microsoft.com/en-us/graph/api/resources/federatedidentitycredentials-overview?view=graph-rest-beta) to authenticate to Kubernetes clusters with Azure AD integration. This works by setting the environment variables:
* `AZURE_CLIENT_ID` is Azure Active Directory application ID that is federated with workload identity
* `AZURE_TENANT_ID` is Azure Active Directory tenant ID
* `AZURE_FEDERATED_TOKEN_FILE` is the file containing signed assertion of workload identity. E.g. Kubernetes projected service account (jwt) token
* `AZURE_AUTHORITY_HOST` is the base URL of an Azure Active Directory authority. E.g. `https://login.microsoftonline.com/`

With workload identity, it's possible to access Kubernetes clusters from CI/CD system such as Github, ArgoCD, etc. without storing Service Principal credentials in those external systems. To learn more, [here](https://github.com/weinong/azure-federated-identity-samples) is a sample to setup OIDC federation from Github.

In this login mode, token will not be cached on the filesystem.

## Usage Examples

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l workloadidentity

kubectl get nodes
```
07070100000039000081A4000000000000000000000001687816E50000027D000000000000000000000000000000000000002F00000000kubelogin-0.2.10/docs/book/src/contributing.md# Contributing

The Azure Kubelogin project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit [https://cla.microsoft.com](https://cla.microsoft.com).

When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. Contributing
0707010000003A000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002B00000000kubelogin-0.2.10/docs/book/src/development0707010000003B000081A4000000000000000000000001687816E50000000E000000000000000000000000000000000000002E00000000kubelogin-0.2.10/docs/book/src/development.md# Development
0707010000003C000081A4000000000000000000000001687816E500000432000000000000000000000000000000000000003800000000kubelogin-0.2.10/docs/book/src/development/releasing.md# Releasing

To make a new release and publish please follow the following steps.

1. Create a branch `publish-x.y.z`
2. Add a section to `CHANGELOG.md` with the header `## [x.y.z]` (N.B: make sure to write the new version in square brackets as the `changelog-reader` action only works if the `CHANGELOG.md` file follows the [Keep a Changelog standard](https://github.com/olivierlacan/keep-a-changelog))
3. Create a new PR, get approval and merge
4. Run the `release` workflow manually from the GH Actions tab

### Sample Changelog content for first release.

For first release using new release and publish using changelog here is a sample:

```

## [0.0.26]

* What is getting released here + @commit

Thanks to whoever was involved, pm.

```

### In Event of Special Case Failures Post Build and Release.

In an event where build and release were successful but publish failed for something else, in that case please make sure we delete the unsucessful release note and release tag, before re-running the release again, this will get release fresh release notes and tag.
0707010000003D000081A4000000000000000000000001687816E5000007AC000000000000000000000000000000000000002A00000000kubelogin-0.2.10/docs/book/src/install.md# Installation

## Download from Release

Copy the latest [Releases](https://github.com/Azure/kubelogin/releases) to shell's search path.

## Homebrew

```sh
# install
brew install Azure/kubelogin/kubelogin

# upgrade
brew update
brew upgrade Azure/kubelogin/kubelogin
```

## Linux

### Using [asdf](https://asdf-vm.com/)

_asdf and the asdf-kubelogin plugin are not maintained by Microsoft._

```sh
# install
asdf plugin add kubelogin
asdf install kubelogin latest
asdf global kubelogin latest

# upgrade
asdf update
asdf plugin update kubelogin
asdf install kubelogin latest
asdf global kubelogin latest
```
### Using azure cli
There is another option to install Kubectl and Kubectl login. Documentation on this is [here](https://learn.microsoft.com/en-us/cli/azure/aks?view=azure-cli-latest#az-aks-install-cli)

```
# install (May require using the command ‘sudo’)
az aks install-cli
```

## Windows

### Using winget

From Powershell:

```powershell
winget install --id=Kubernetes.kubectl  -e
winget install --id=Microsoft.Azure.Kubelogin  -e
```

### Using scoop

This package is not maintained by Microsoft.

From Powershell:

```powershell
scoop install kubectl azure-kubelogin
```

### Using chocolatey

This package is not maintained by Microsoft.

From Powershell:

```powershell
choco install kubernetes-cli azure-kubelogin
```

### Using azure cli

From Powershell:

```powershell
az aks install-cli
$targetDir="$env:USERPROFILE\.azure-kubelogin"
$oldPath = [System.Environment]::GetEnvironmentVariable("Path","User")
$oldPathArray=($oldPath) -split ";"
if(-Not($oldPathArray -Contains "$targetDir")) {
    write-host "Permanently adding $targetDir to User Path"
    $newPath = "$oldPath;$targetDir" -replace ";+", ";"
    [System.Environment]::SetEnvironmentVariable("Path",$newPath,"User")
    $env:Path = [System.Environment]::GetEnvironmentVariable("Path","User"),[System.Environment]::GetEnvironmentVariable("Path","Machine") -join ";"
}
```
0707010000003E000081A4000000000000000000000001687816E50000000F000000000000000000000000000000000000002F00000000kubelogin-0.2.10/docs/book/src/installation.md# Installation
0707010000003F000081A4000000000000000000000001687816E500000478000000000000000000000000000000000000002F00000000kubelogin-0.2.10/docs/book/src/known-issues.md# Known Issues

* [Maximum 200 groups will be included in the Azure AD JWT](https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-fed-group-claims). 
For more than 200 groups, consider using [Application Roles](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps)
* Groups created in Azure AD can only be included by their ObjectID and not name, as [`sAMAccountName` is only available for groups synchronized from Active Directory](https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-fed-group-claims#group-claims-for-applications-migrating-from-ad-fs-and-other-identity-providers)
* [`kubelogin` may not work with MSI when run in Azure Container Instance](https://github.com/Azure/kubelogin/issues/79)
* On AKS, [service principal](./concepts/login-modes/sp.md) login mode will only work with managed AAD, not legacy AAD.
* [Device code](./concepts/login-modes/devicecode.md) login mode does not work when Conditional Access policy is configured on Azure AD tenant.
Use [web browser interactive](./concepts/login-modes/interactive.md) instead.
07070100000040000081A4000000000000000000000001687816E500000437000000000000000000000000000000000000002E00000000kubelogin-0.2.10/docs/book/src/maintenance.md## How to Release

To make a new release and publish please follow the following steps.

1. Create a branch `publish-x.y.z`
2. Add a section to `CHANGELOG.md` with the header `## [x.y.z]` (N.B: make sure to write the new version in square brackets as the `changelog-reader` action only works if the `CHANGELOG.md` file follows the [Keep a Changelog standard](https://github.com/olivierlacan/keep-a-changelog))
3. Create a new PR, get approval and merge
4. Run the `release` workflow manually from the GH Actions tab

### Sample Changelog content for first release.

For first release using new release and publish using changelog here is a sample:

```

## [0.0.26]

* What is getting released here + @commit

Thanks to whoever was involved, pm.

```

### In Event of Special Case Failures Post Build and Release.

In an event where build and release were successful but publish failed for something else, in that case please make sure we delete the unsucessful release note and release tag, before re-running the release again, this will get release fresh release notes and tag.07070100000041000081A4000000000000000000000001687816E5000001F6000000000000000000000000000000000000002E00000000kubelogin-0.2.10/docs/book/src/quick-start.md# Quick Start

After `kubelogin` is installed, do the following on Azure AD enabled AKS clusters

## Using Azure CLI login mode

```sh
az login

# by default, this command merges the kubeconfig into ${HOME}/.kube/config
az aks get-credentials -g ${RESOURCE_GROUP_NAME} -n ${AKS_NAME}


# kubelogin by default will use the kubeconfig from ${KUBECONFIG}. Specify --kubeconfig to override
# this converts to use azurecli login mode
kubelogin convert-kubeconfig -l azurecli

# voila!
kubectl get nodes
```
07070100000042000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002600000000kubelogin-0.2.10/docs/book/src/topics07070100000043000081A4000000000000000000000001687816E50000004D000000000000000000000000000000000000002900000000kubelogin-0.2.10/docs/book/src/topics.md# Topics

This section documents different usages of `kubelogin` in details.
07070100000044000081A4000000000000000000000001687816E5000005B3000000000000000000000000000000000000003600000000kubelogin-0.2.10/docs/book/src/topics/environments.md# Using in different environments

`kubelogin` supports Azure Environments:

- AzurePublicCloud (default value)
- AzureChinaCloud
- AzureUSGovernmentCloud
- AzureStackCloud

You can specify `--environment` in `kubelogin convert-kubeconfig`.

When using `AzureStackCloud` you will need to specify the actual endpoints in a config file, and set the environment variable `AZURE_ENVIRONMENT_FILEPATH` to that file.

The configuration parameters of this file:

```json
{
  "name": "AzureStackCloud",
  "managementPortalURL": "...",
  "publishSettingsURL": "...",
  "serviceManagementEndpoint": "...",
  "resourceManagerEndpoint": "...",
  "activeDirectoryEndpoint": "...",
  "galleryEndpoint": "...",
  "keyVaultEndpoint": "...",
  "graphEndpoint": "...",
  "serviceBusEndpoint": "...",
  "batchManagementEndpoint": "...",
  "storageEndpointSuffix": "...",
  "sqlDatabaseDNSSuffix": "...",
  "trafficManagerDNSSuffix": "...",
  "keyVaultDNSSuffix": "...",
  "serviceBusEndpointSuffix": "...",
  "serviceManagementVMDNSSuffix": "...",
  "resourceManagerVMDNSSuffix": "...",
  "containerRegistryDNSSuffix": "...",
  "cosmosDBDNSSuffix": "...",
  "tokenAudience": "...",
  "resourceIdentifiers": {
    "graph": "...",
    "keyVault": "...",
    "datalake": "...",
    "batch": "...",
    "operationalInsights": "..."
  }
}
```

The full configuration is available in the source code at <https://github.com/Azure/go-autorest/blob/main/autorest/azure/environments.go>.
07070100000045000081A4000000000000000000000001687816E500000700000000000000000000000000000000000000003100000000kubelogin-0.2.10/docs/book/src/topics/jenkins.md# Using kubelogin in Jenkins

In Jenkins, since workspaces are most likely run under `jenkins` user, different login modes may have different configuration requirements to allow multiple builds to run concurrently. When it is not configured properly, there may be clashing in cache or login context that results in `You must be logged in to the server (Unauthorized)` error message.

## Using Azure CLI Login mode

When Azure CLI is installed in Jenkins environment, Azure CLI's config directory likely resides in Jenkins workspace directory. To use the Azure CLI, environment variable `AZURE_CONFIG_DIR` should be specified.

Using kubelogin `convert-kubeconfig` subcommand with `--azure-config-dir`, the generated kubeconfig will configure the environment variable for `get-token` subcommand to find the corresponding Azure config directory. For example,

```sh
stage('Download kubeconfig and convert') {
    steps {
        sh 'az aks get-credentials -g ${RESOURCE_GROUP} -n ${CLUSTER_NAME}'
        sh 'kubelogin convert-kubeconfig -l azurecli --azure-config-dir ${AZURE_CONFIG_DIR:-${WORKSPACE}/.azure}'
    }
}

stage('Run kubectl') {
    steps {
        sh 'kubectl get nodes'
    }
}
```

## Using Device Code, Web Browser, and ROPC Login Modes

Since `kubelogin` by default caches authentication record (a json file containing user identification such as object ID and tenant ID) at `${HOME}/.kube/cache/kubelogin/auth.json` in [device code](../concepts/login-modes/devicecode.md),
[web browser interactive](../concepts/login-modes/interactive.md), and [ropc](../concepts/login-modes/ropc.md) [login modes](../concepts/login-modes.md),
`kubelogin covert-kubeconfig --cache-dir` should be specified to a directory under Jenkins workspace such as `${WORKSPACE}/.kube/cache/kubelogin`.
07070100000046000081A4000000000000000000000001687816E50000074A000000000000000000000000000000000000003600000000kubelogin-0.2.10/docs/book/src/topics/k8s-oidc-aad.md# Setup k8s OIDC Provider using Azure AD

`kubelogin` can be used to authenticate to general kubernetes clusters using AAD as an OIDC provider. 

1. Create an AAD Enterprise Application and the corresponding App Registration. Check the `Allow public client flows` checkbox. 
Configure groups to be included in the response. Take a note of the directory (tenant) ID as `$AAD_TENANT_ID` and the application (client) ID as `$AAD_CLIENT_ID`
1. Configure the API server with the following flags:

   * Issuer URL: `--oidc-issuer-url=https://sts.windows.net/$AAD_TENANT_ID/`
   * Client ID: `--oidc-client-id=$AAD_CLIENT_ID`
   * Username claim: `--oidc-username-claim=upn`

   See the [kubernetes docs for optional flags](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuring-the-api-server). For EKS clusters [configure this on the Management Console](https://docs.amazonaws.cn/en_us/eks/latest/userguide/authenticate-oidc-identity-provider.html) or via [terraform](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_identity_provider_config).

3. Configure the [Exec plugin](../concepts/exec-plugin.md) with `kubelogin` to use the application from the first step:

   ```sh
   kubectl config set-credentials "azure-user" \
     --exec-api-version=client.authentication.k8s.io/v1beta1 \
     --exec-command=kubelogin \
     --exec-arg=get-token \
     --exec-arg=--environment \
     --exec-arg=AzurePublicCloud \
     --exec-arg=--server-id \
     --exec-arg=$AAD_CLIENT_ID \
     --exec-arg=--client-id \
     --exec-arg=$AAD_CLIENT_ID \
     --exec-arg=--tenant-id \
     --exec-arg=$AAD_TENANT_ID
   ```

4. Use this credential to connect to the cluster:

   ```
   kubectl config set-context "$CLUSTER_NAME" --cluster="$CLUSTER_NAME" --user=azure-user
   kubectl config use-context "$CLUSTER_NAME"
   ```

07070100000047000081A4000000000000000000000001687816E50000065E000000000000000000000000000000000000002C00000000kubelogin-0.2.10/docs/book/src/topics/sp.md# Using Service Principal

This section documents the end to end flow to use `kubelogin` to access AKS cluster with a service principal.

## 1. Create a service principal or use an existing one.

```sh
az ad sp create-for-rbac --skip-assignment --name myAKSAutomationServicePrincipal
```

The output is similar to the following example.

```json
{
  "appId": "<spn client id>",
  "displayName": "myAKSAutomationServicePrincipal",
  "name": "http://myAKSAutomationServicePrincipal",
  "password": "<spn secret>",
  "tenant": "<aad tenant id>"
}
```

## 2. Query your service principal AAD Object ID by using the command below.

```sh
az ad sp show --id <spn client id> --query "id"
```

## 3. To configure the role binding on Azure Kubernetes Service, the user in rolebinding should be the SP's Object ID.

For example,

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: sp-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: <service-principal-object-id>
```

## 4. Use `kubelogin` to convert the kubeconfig

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l spn

export AAD_SERVICE_PRINCIPAL_CLIENT_ID=<spn client id>
export AAD_SERVICE_PRINCIPAL_CLIENT_SECRET=<spn secret>

kubectl get nodes
```

or write your spn secret permanently into the kubeconfig (not preferred!):

```sh
export KUBECONFIG=/path/to/kubeconfig

kubelogin convert-kubeconfig -l spn --client-id <spn client id> --client-secret <spn secret>

kubectl get nodes
```
07070100000048000081A4000000000000000000000001687816E5000010C3000000000000000000000000000000000000001800000000kubelogin-0.2.10/go.modmodule github.com/Azure/kubelogin

// NOTE: kubelogin follows the same support policy as Go, which supports the last two major versions.
go 1.23.11

require (
	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0
	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0
	github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0
	github.com/Azure/go-autorest/autorest v0.11.29
	github.com/Azure/go-autorest/autorest/adal v0.9.23
	github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2
	github.com/golang-jwt/jwt/v4 v4.5.2
	github.com/google/go-cmp v0.6.0
	github.com/google/uuid v1.6.0
	github.com/spf13/cobra v1.8.1
	github.com/spf13/pflag v1.0.5
	github.com/stretchr/testify v1.9.0
	go.uber.org/mock v0.5.0
	golang.org/x/crypto v0.40.0
	gopkg.in/dnaeon/go-vcr.v4 v4.0.2
	k8s.io/apimachinery v0.29.3
	k8s.io/cli-runtime v0.29.3
	k8s.io/client-go v0.29.3
	k8s.io/klog/v2 v2.130.1
)

require (
	github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
	github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
	github.com/Azure/go-autorest v14.2.0+incompatible // indirect
	github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
	github.com/Azure/go-autorest/logger v0.2.1 // indirect
	github.com/Azure/go-autorest/tracing v0.6.0 // indirect
	github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 // indirect
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/emicklei/go-restful/v3 v3.11.0 // indirect
	github.com/evanphx/json-patch v5.6.0+incompatible // indirect
	github.com/go-errors/errors v1.4.2 // indirect
	github.com/go-logr/logr v1.4.1 // indirect
	github.com/go-openapi/jsonpointer v0.19.6 // indirect
	github.com/go-openapi/jsonreference v0.20.2 // indirect
	github.com/go-openapi/swag v0.22.3 // indirect
	github.com/gogo/protobuf v1.3.2 // indirect
	github.com/golang-jwt/jwt/v5 v5.2.3 // indirect
	github.com/golang/protobuf v1.5.4 // indirect
	github.com/google/btree v1.1.2 // indirect
	github.com/google/gnostic-models v0.6.8 // indirect
	github.com/google/gofuzz v1.2.0 // indirect
	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
	github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
	github.com/imdario/mergo v0.3.13 // indirect
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
	github.com/josharian/intern v1.0.0 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 // indirect
	github.com/kylelemons/godebug v1.1.0 // indirect
	github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
	github.com/mailru/easyjson v0.7.7 // indirect
	github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
	github.com/modern-go/reflect2 v1.0.2 // indirect
	github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
	github.com/pkg/errors v0.9.1 // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	github.com/xlab/treeprint v1.2.0 // indirect
	go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
	golang.org/x/net v0.41.0 // indirect
	golang.org/x/oauth2 v0.30.0 // indirect
	golang.org/x/sync v0.16.0 // indirect
	golang.org/x/sys v0.34.0 // indirect
	golang.org/x/term v0.33.0 // indirect
	golang.org/x/text v0.27.0 // indirect
	golang.org/x/time v0.3.0 // indirect
	google.golang.org/protobuf v1.33.0 // indirect
	gopkg.in/inf.v0 v0.9.1 // indirect
	gopkg.in/yaml.v2 v2.4.0 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
	k8s.io/api v0.29.3 // indirect
	k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
	k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
	sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
	sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
	sigs.k8s.io/yaml v1.3.0 // indirect
)
07070100000049000081A4000000000000000000000001687816E500007D19000000000000000000000000000000000000001800000000kubelogin-0.2.10/go.sumcloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw=
github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs=
github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk=
github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8=
github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=
github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0=
github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4=
github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/dnaeon/go-vcr.v4 v4.0.2 h1:7T5VYf2ifyK01ETHbJPl5A6XTpUljD4Trw3GEDcdedk=
gopkg.in/dnaeon/go-vcr.v4 v4.0.2/go.mod h1:65yxh9goQVrudqofKtHA4JNFWd6XZRkWfKN4YpMx7KI=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw=
k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80=
k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU=
k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU=
k8s.io/cli-runtime v0.29.3 h1:r68rephmmytoywkw2MyJ+CxjpasJDQY7AGc3XY2iv1k=
k8s.io/cli-runtime v0.29.3/go.mod h1:aqVUsk86/RhaGJwDhHXH0jcdqBrgdF3bZWk4Z9D4mkM=
k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg=
k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U=
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
0707010000004A000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001600000000kubelogin-0.2.10/hack0707010000004B000081ED000000000000000000000001687816E500000238000000000000000000000000000000000000002C00000000kubelogin-0.2.10/hack/install-mdbook-toc.sh#!/bin/bash

set -o errexit
set -o nounset
set -o pipefail

VERSION=${1}
OUTPUT_PATH=${2}

# Ensure the output folder exists
mkdir -p "${OUTPUT_PATH}"

RELEASE_NAME=""
case "$OSTYPE" in
  darwin*) RELEASE_NAME="x86_64-apple-darwin.tar.gz"  ;;
  linux*)  RELEASE_NAME="x86_64-unknown-linux-gnu.tar.gz" ;;
  *)       echo "No mdBook release available for: $OSTYPE" && exit 1;;
esac

# Download and extract the mdBook release
curl -L "https://github.com/badboy/mdbook-toc/releases/download/${VERSION}/mdbook-toc-${VERSION}-${RELEASE_NAME}" | tar -xvz -C "${OUTPUT_PATH}"
0707010000004C000081ED000000000000000000000001687816E500000233000000000000000000000000000000000000002800000000kubelogin-0.2.10/hack/install-mdbook.sh#!/bin/bash

set -o errexit
set -o nounset
set -o pipefail

VERSION=${1}
OUTPUT_PATH=${2}

# Ensure the output folder exists
mkdir -p "${OUTPUT_PATH}"

RELEASE_NAME=""
case "$OSTYPE" in
  darwin*) RELEASE_NAME="x86_64-apple-darwin.tar.gz"  ;;
  linux*)  RELEASE_NAME="x86_64-unknown-linux-gnu.tar.gz" ;;
  *)       echo "No mdBook release available for: $OSTYPE" && exit 1;;
esac

# Download and extract the mdBook release
curl -L "https://github.com/rust-lang/mdBook/releases/download/${VERSION}/mdbook-${VERSION}-${RELEASE_NAME}" | tar -xvz -C "${OUTPUT_PATH}"
0707010000004D000081A4000000000000000000000001687816E5000001BF000000000000000000000000000000000000001900000000kubelogin-0.2.10/main.gopackage main

import (
	"flag"
	"os"

	"github.com/Azure/kubelogin/pkg/cmd"
	"github.com/spf13/pflag"
	klog "k8s.io/klog/v2"
)

func main() {
	klog.InitFlags(nil)
	pflag.CommandLine.AddGoFlag(flag.CommandLine.Lookup("v"))
	pflag.CommandLine.AddGoFlag(flag.CommandLine.Lookup("logtostderr"))
	_ = pflag.CommandLine.Set("logtostderr", "true")
	root := cmd.NewRootCmd(loadVersion().String())
	if err := root.Execute(); err != nil {
		os.Exit(1)
	}
}
0707010000004E000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001500000000kubelogin-0.2.10/pkg0707010000004F000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001900000000kubelogin-0.2.10/pkg/cmd07070100000050000081A4000000000000000000000001687816E500000395000000000000000000000000000000000000002400000000kubelogin-0.2.10/pkg/cmd/convert.gopackage cmd

import (
	"github.com/Azure/kubelogin/pkg/internal/converter"
	"github.com/spf13/cobra"
	"k8s.io/client-go/tools/clientcmd"
)

// newConvertCmd provides a cobra command for convert sub command
func newConvertCmd() *cobra.Command {
	o := converter.New()

	cmd := &cobra.Command{
		Use:          "convert-kubeconfig",
		Short:        "convert kubeconfig to use exec auth module",
		SilenceUsage: true,
		RunE: func(c *cobra.Command, args []string) error {
			o.Flags = c.Flags()
			o.UpdateFromEnv()

			if err := o.Validate(); err != nil {
				return err
			}

			pathOptions := clientcmd.NewDefaultPathOptions()
			pathOptions.LoadingRules.ExplicitPath, _ = o.Flags.GetString("kubeconfig")

			if err := converter.Convert(o, pathOptions); err != nil {
				return err
			}
			return nil
		},
		ValidArgsFunction: cobra.NoFileCompletions,
	}

	o.AddFlags(cmd.Flags())
	o.AddCompletions(cmd)

	return cmd
}
07070100000051000081A4000000000000000000000001687816E500000389000000000000000000000000000000000000002B00000000kubelogin-0.2.10/pkg/cmd/removecachedir.gopackage cmd

import (
	"os"

	"github.com/Azure/kubelogin/pkg/internal/token"
	"github.com/spf13/cobra"
	klog "k8s.io/klog/v2"
)

// newRemoveAuthRecordCacheCmd provides a cobra command for removing token cache sub command
func newRemoveAuthRecordCacheCmd() *cobra.Command {
	var authRecordCacheDir string

	cmd := &cobra.Command{
		Use:          "remove-cache-dir",
		Short:        "Remove all cached authentication record from filesystem",
		SilenceUsage: true,
		RunE: func(c *cobra.Command, args []string) error {
			if err := os.RemoveAll(authRecordCacheDir); err != nil {
				klog.V(5).Infof("unable to delete authentication record cache in '%s': %s", authRecordCacheDir, err)
			}
			return nil
		},
		ValidArgsFunction: cobra.NoFileCompletions,
	}

	cmd.Flags().StringVar(&authRecordCacheDir, "cache-dir", token.DefaultAuthRecordCacheDir, "directory to cache authentication record")
	return cmd
}
07070100000052000081A4000000000000000000000001687816E5000003E8000000000000000000000000000000000000002D00000000kubelogin-0.2.10/pkg/cmd/removetokencache.gopackage cmd

import (
	"os"

	"github.com/Azure/kubelogin/pkg/internal/token"
	"github.com/spf13/cobra"
	klog "k8s.io/klog/v2"
)

// newRemoveAuthRecordCacheCmd provides a cobra command for removing token cache sub command
func newRemoveAuthRecordCacheCmdDeprecated() *cobra.Command {
	var authRecordCacheDir string

	cmd := &cobra.Command{
		Use:          "remove-tokens",
		Short:        "Remove all cached authentication record from filesystem",
		SilenceUsage: true,
		RunE: func(c *cobra.Command, args []string) error {
			if err := os.RemoveAll(authRecordCacheDir); err != nil {
				klog.V(5).Infof("unable to delete authentication record cache in '%s': %s", authRecordCacheDir, err)
			}
			return nil
		},
		ValidArgsFunction: cobra.NoFileCompletions,
		Deprecated:        "remove-tokens is deprecated, use remove-cache-dir instead",
	}

	cmd.Flags().StringVar(&authRecordCacheDir, "token-cache-dir", token.DefaultAuthRecordCacheDir, "directory to cache authentication record")
	return cmd
}
07070100000053000081A4000000000000000000000001687816E500000259000000000000000000000000000000000000002100000000kubelogin-0.2.10/pkg/cmd/root.gopackage cmd

import (
	"github.com/spf13/cobra"
)

// NewRootCmd provides a cobra root command
func NewRootCmd(version string) *cobra.Command {

	cmd := &cobra.Command{
		Use:          "kubelogin",
		Short:        "login to azure active directory and populate kubeconfig with AAD tokens",
		SilenceUsage: true,
		Version:      version,
		RunE: func(c *cobra.Command, args []string) error {
			return c.Help()
		},
	}

	cmd.AddCommand(newConvertCmd())
	cmd.AddCommand(newTokenCmd())
	cmd.AddCommand(newRemoveAuthRecordCacheCmdDeprecated())
	cmd.AddCommand(newRemoveAuthRecordCacheCmd())

	return cmd
}
07070100000054000081A4000000000000000000000001687816E50000036F000000000000000000000000000000000000002200000000kubelogin-0.2.10/pkg/cmd/token.gopackage cmd

import (
	"context"
	"os"
	"os/signal"

	"github.com/Azure/kubelogin/pkg/internal/token"
	"github.com/spf13/cobra"
)

// newTokenCmd provides a cobra command for convert sub command
func newTokenCmd() *cobra.Command {
	o := token.NewOptions(true)

	cmd := &cobra.Command{
		Use:          "get-token",
		Short:        "get AAD token",
		SilenceUsage: true,
		RunE: func(c *cobra.Command, args []string) error {
			o.UpdateFromEnv()

			ctx := context.Background()
			ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
			defer cancel()

			if err := o.Validate(); err != nil {
				return err
			}

			plugin, err := token.New(&o)
			if err != nil {
				return err
			}
			if err := plugin.Do(ctx); err != nil {
				return err
			}
			return nil
		},
		ValidArgsFunction: cobra.NoFileCompletions,
	}

	o.AddFlags(cmd.Flags())
	o.AddCompletions(cmd)

	return cmd
}
07070100000055000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001E00000000kubelogin-0.2.10/pkg/internal07070100000056000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002800000000kubelogin-0.2.10/pkg/internal/converter07070100000057000081A4000000000000000000000001687816E500003C69000000000000000000000000000000000000003300000000kubelogin-0.2.10/pkg/internal/converter/convert.gopackage converter

import (
	"fmt"
	"strings"

	"github.com/Azure/kubelogin/pkg/internal/token"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/tools/clientcmd/api"
	klog "k8s.io/klog/v2"
)

const (
	azureAuthProvider = "azure"
	cfgClientID       = "client-id"
	cfgApiserverID    = "apiserver-id"
	cfgTenantID       = "tenant-id"
	cfgEnvironment    = "environment"
	cfgConfigMode     = "config-mode"

	argClientID                   = "--client-id"
	argServerID                   = "--server-id"
	argTenantID                   = "--tenant-id"
	argEnvironment                = "--environment"
	argClientSecret               = "--client-secret"
	argClientCert                 = "--client-certificate"
	argClientCertPassword         = "--client-certificate-password"
	argIsLegacy                   = "--legacy"
	argUsername                   = "--username"
	argPassword                   = "--password"
	argLoginMethod                = "--login"
	argIdentityResourceID         = "--identity-resource-id"
	argAuthorityHost              = "--authority-host"
	argFederatedTokenFile         = "--federated-token-file"
	argTokenCacheDir              = "--token-cache-dir"
	argAuthRecordCacheDir         = "--cache-dir"
	argIsPoPTokenEnabled          = "--pop-enabled"
	argPoPTokenClaims             = "--pop-claims"
	argDisableEnvironmentOverride = "--disable-environment-override"
	argRedirectURL                = "--redirect-url"
	argLoginHint                  = "--login-hint"

	flagAzureConfigDir             = "azure-config-dir"
	flagClientID                   = "client-id"
	flagContext                    = "context"
	flagServerID                   = "server-id"
	flagTenantID                   = "tenant-id"
	flagEnvironment                = "environment"
	flagClientSecret               = "client-secret"
	flagClientCert                 = "client-certificate"
	flagClientCertPassword         = "client-certificate-password"
	flagIsLegacy                   = "legacy"
	flagUsername                   = "username"
	flagPassword                   = "password"
	flagLoginMethod                = "login"
	flagIdentityResourceID         = "identity-resource-id"
	flagAuthorityHost              = "authority-host"
	flagFederatedTokenFile         = "federated-token-file"
	flagTokenCacheDir              = "token-cache-dir"
	flagAuthRecordCacheDir         = "cache-dir"
	flagIsPoPTokenEnabled          = "pop-enabled"
	flagPoPTokenClaims             = "pop-claims"
	flagDisableEnvironmentOverride = "disable-environment-override"
	flagRedirectURL                = "redirect-url"
	flagLoginHint                  = "login-hint"

	execName        = "kubelogin"
	getTokenCommand = "get-token"
	execAPIVersion  = "client.authentication.k8s.io/v1beta1"
	execInstallHint = `
kubelogin is not installed which is required to connect to AAD enabled cluster.

To learn more, please go to https://azure.github.io/kubelogin/
`

	azureConfigDir = "AZURE_CONFIG_DIR"
)

func getArgValues(o Options, authInfo *api.AuthInfo) (
	argServerIDVal,
	argClientIDVal,
	argEnvironmentVal,
	argTenantIDVal,
	argAuthRecordCacheDirVal,
	argPoPTokenClaimsVal,
	argRedirectURLVal,
	argLoginHintVal string,
	argIsLegacyConfigModeVal,
	argIsPoPTokenEnabledVal bool,
) {
	if authInfo == nil {
		return
	}

	isLegacyAuthProvider := isLegacyAzureAuth(authInfo)

	if o.isSet(flagEnvironment) {
		argEnvironmentVal = o.TokenOptions.Environment
	} else if isLegacyAuthProvider {
		if x, ok := authInfo.AuthProvider.Config[cfgEnvironment]; ok {
			argEnvironmentVal = x
		}
	} else {
		argEnvironmentVal = getExecArg(authInfo, argEnvironment)
	}

	if o.isSet(flagTenantID) {
		argTenantIDVal = o.TokenOptions.TenantID
	} else if isLegacyAuthProvider {
		if x, ok := authInfo.AuthProvider.Config[cfgTenantID]; ok {
			argTenantIDVal = x
		}
	} else {
		argTenantIDVal = getExecArg(authInfo, argTenantID)
	}

	if o.isSet(flagClientID) {
		argClientIDVal = o.TokenOptions.ClientID
	} else if isLegacyAuthProvider {
		if x, ok := authInfo.AuthProvider.Config[cfgClientID]; ok {
			argClientIDVal = x
		}
	} else {
		argClientIDVal = getExecArg(authInfo, argClientID)
	}

	if o.isSet(flagServerID) {
		argServerIDVal = o.TokenOptions.ServerID
	} else if isLegacyAuthProvider {
		if x, ok := authInfo.AuthProvider.Config[cfgApiserverID]; ok {
			argServerIDVal = x
		}
	} else {
		argServerIDVal = getExecArg(authInfo, argServerID)
	}

	if o.isSet(flagIsLegacy) && o.TokenOptions.IsLegacy {
		argIsLegacyConfigModeVal = true
	} else if isLegacyAuthProvider {
		if x := authInfo.AuthProvider.Config[cfgConfigMode]; x == "" || x == "0" {
			argIsLegacyConfigModeVal = true
		}
	} else {
		if found := getExecBoolArg(authInfo, argIsLegacy); found {
			argIsLegacyConfigModeVal = true
		}
	}

	if o.isSet(flagAuthRecordCacheDir) || o.isSet(flagTokenCacheDir) {
		argAuthRecordCacheDirVal = o.TokenOptions.AuthRecordCacheDir
	} else {
		if val := getExecArg(authInfo, argAuthRecordCacheDir); val != "" {
			argAuthRecordCacheDirVal = val
		} else {
			argAuthRecordCacheDirVal = getExecArg(authInfo, argTokenCacheDir)
		}
	}

	if o.isSet(flagIsPoPTokenEnabled) {
		argIsPoPTokenEnabledVal = o.TokenOptions.IsPoPTokenEnabled
	} else {
		if found := getExecBoolArg(authInfo, argIsPoPTokenEnabled); found {
			argIsPoPTokenEnabledVal = true
		}
	}

	if o.isSet(flagPoPTokenClaims) {
		argPoPTokenClaimsVal = o.TokenOptions.PoPTokenClaims
	} else {
		argPoPTokenClaimsVal = getExecArg(authInfo, argPoPTokenClaims)
	}

	if o.isSet(flagRedirectURL) {
		argRedirectURLVal = o.TokenOptions.RedirectURL
	} else {
		argRedirectURLVal = getExecArg(authInfo, argRedirectURL)
	}

	if o.isSet(flagLoginHint) {
		argLoginHintVal = o.TokenOptions.LoginHint
	} else {
		argLoginHintVal = getExecArg(authInfo, argLoginHint)
	}

	return
}

func isLegacyAzureAuth(authInfoPtr *api.AuthInfo) (ok bool) {
	if authInfoPtr == nil {
		return
	}
	if authInfoPtr.AuthProvider == nil {
		return
	}
	return authInfoPtr.AuthProvider.Name == azureAuthProvider
}

func isExecUsingkubelogin(authInfoPtr *api.AuthInfo) (ok bool) {
	if authInfoPtr == nil {
		return
	}
	if authInfoPtr.Exec == nil {
		return
	}
	lowerc := strings.ToLower(authInfoPtr.Exec.Command)
	return strings.Contains(lowerc, "kubelogin")
}

func Convert(o Options, pathOptions *clientcmd.PathOptions) error {
	clientConfig := o.configFlags.ToRawKubeConfigLoader()
	var kubeconfigs []string

	klog.V(5).Info(o.ToString())

	if clientConfig.ConfigAccess() != nil {
		if clientConfig.ConfigAccess().GetExplicitFile() != "" {
			kubeconfigs = append(kubeconfigs, clientConfig.ConfigAccess().GetExplicitFile())
		} else {
			kubeconfigs = append(kubeconfigs, clientConfig.ConfigAccess().GetLoadingPrecedence()...)
		}
	}

	klog.V(5).Infof("Loading kubeconfig from %s", strings.Join(kubeconfigs, ":"))

	config, err := clientConfig.RawConfig()
	if err != nil {
		return fmt.Errorf("unable to load kubeconfig: %s", err)
	}

	targetAuthInfo := ""

	if o.context != "" {
		if config.Contexts[o.context] == nil {
			return fmt.Errorf("no context exists with the name: %q", o.context)
		}
		targetAuthInfo = config.Contexts[o.context].AuthInfo
	}

	for name, authInfo := range config.AuthInfos {

		if targetAuthInfo != "" && name != targetAuthInfo {
			continue
		}

		klog.V(5).Infof("context: %q", name)

		//  is it legacy aad auth or is it exec using kubelogin?
		if !isExecUsingkubelogin(authInfo) && !isLegacyAzureAuth(authInfo) {
			continue
		}

		klog.V(5).Info("converting...")

		argServerIDVal,
			argClientIDVal,
			argEnvironmentVal,
			argTenantIDVal,
			argAuthRecordCacheDirVal,
			argPoPTokenClaimsVal,
			argRedirectURLVal,
			argLoginHintVal,
			isLegacyConfigMode,
			isPoPTokenEnabled := getArgValues(o, authInfo)
		exec := &api.ExecConfig{
			Command: execName,
			Args: []string{
				getTokenCommand,
			},
			APIVersion:  execAPIVersion,
			InstallHint: execInstallHint,
		}

		// Preserve any existing install hint
		if authInfo.Exec != nil && authInfo.Exec.InstallHint != "" {
			exec.InstallHint = authInfo.Exec.InstallHint
		}

		exec.Args = append(exec.Args, argLoginMethod, o.TokenOptions.LoginMethod)

		// all login methods require --server-id specified
		if argServerIDVal == "" {
			return fmt.Errorf("%s is required", argServerID)
		}
		exec.Args = append(exec.Args, argServerID, argServerIDVal)

		if argAuthRecordCacheDirVal != "" {
			exec.Args = append(exec.Args, argAuthRecordCacheDir, argAuthRecordCacheDirVal)
		}

		switch o.TokenOptions.LoginMethod {
		case token.AzureDeveloperCLILogin:
			if o.isSet(flagTenantID) {
				exec.Args = append(exec.Args, argTenantID, o.TokenOptions.TenantID)
			}

		case token.AzureCLILogin:

			if o.azureConfigDir != "" {
				exec.Env = append(exec.Env, api.ExecEnvVar{Name: azureConfigDir, Value: o.azureConfigDir})
			}

			// when convert to azurecli login, tenantID from the input kubeconfig will be disregarded and
			// will have to come from explicit flag `--tenant-id`.
			// this is because azure cli logged in using MSI does not allow specifying tenant ID
			// see https://github.com/Azure/kubelogin/issues/123#issuecomment-1209652342
			if o.isSet(flagTenantID) {
				exec.Args = append(exec.Args, argTenantID, o.TokenOptions.TenantID)
			}

		case token.DeviceCodeLogin:

			if argClientIDVal == "" {
				return fmt.Errorf("%s is required", argClientID)
			}

			exec.Args = append(exec.Args, argClientID, argClientIDVal)

			if argTenantIDVal == "" {
				return fmt.Errorf("%s is required", argTenantID)
			}

			exec.Args = append(exec.Args, argTenantID, argTenantIDVal)

			if argEnvironmentVal != "" {
				// environment is optional
				exec.Args = append(exec.Args, argEnvironment, argEnvironmentVal)
			}

			if isLegacyConfigMode {
				exec.Args = append(exec.Args, argIsLegacy)
			}

		case token.InteractiveLogin:

			if argClientIDVal == "" {
				return fmt.Errorf("%s is required", argClientID)
			}

			exec.Args = append(exec.Args, argClientID, argClientIDVal)

			if argTenantIDVal == "" {
				return fmt.Errorf("%s is required", argTenantID)
			}

			exec.Args = append(exec.Args, argTenantID, argTenantIDVal)

			if argEnvironmentVal != "" {
				// environment is optional
				exec.Args = append(exec.Args, argEnvironment, argEnvironmentVal)
			}

			// PoP token flags are optional but must be provided together
			exec.Args, err = validatePoPClaims(exec.Args, isPoPTokenEnabled, argPoPTokenClaims, argPoPTokenClaimsVal)
			if err != nil {
				return err
			}

			if argRedirectURLVal != "" {
				exec.Args = append(exec.Args, argRedirectURL, argRedirectURLVal)
			}

			if argLoginHintVal != "" {
				exec.Args = append(exec.Args, argLoginHint, argLoginHintVal)
			}

		case token.ServicePrincipalLogin:

			if argClientIDVal == "" {
				return fmt.Errorf("%s is required", argClientID)
			}

			exec.Args = append(exec.Args, argClientID, argClientIDVal)

			if argTenantIDVal == "" {
				return fmt.Errorf("%s is required", argTenantID)
			}

			exec.Args = append(exec.Args, argTenantID, argTenantIDVal)

			if argEnvironmentVal != "" {
				// environment is optional
				exec.Args = append(exec.Args, argEnvironment, argEnvironmentVal)
			}

			if o.isSet(flagClientSecret) {
				exec.Args = append(exec.Args, argClientSecret, o.TokenOptions.ClientSecret)
			}

			if o.isSet(flagClientCert) {
				exec.Args = append(exec.Args, argClientCert, o.TokenOptions.ClientCert)
			}

			if o.isSet(flagClientCertPassword) {
				exec.Args = append(exec.Args, argClientCertPassword, o.TokenOptions.ClientCertPassword)
			}

			if isLegacyConfigMode {
				exec.Args = append(exec.Args, argIsLegacy)
			}

			// PoP token flags are optional but must be provided together
			exec.Args, err = validatePoPClaims(exec.Args, isPoPTokenEnabled, argPoPTokenClaims, argPoPTokenClaimsVal)
			if err != nil {
				return err
			}

			if o.isSet(flagDisableEnvironmentOverride) {
				exec.Args = append(exec.Args, argDisableEnvironmentOverride)
			}

		case token.MSILogin:

			if o.isSet(flagClientID) {
				exec.Args = append(exec.Args, argClientID, o.TokenOptions.ClientID)
			} else if o.isSet(flagIdentityResourceID) {
				exec.Args = append(exec.Args, argIdentityResourceID, o.TokenOptions.IdentityResourceID)
			}

		case token.ROPCLogin:

			if argClientIDVal == "" {
				return fmt.Errorf("%s is required", argClientID)
			}

			exec.Args = append(exec.Args, argClientID, argClientIDVal)

			if argTenantIDVal == "" {
				return fmt.Errorf("%s is required", argTenantID)
			}

			exec.Args = append(exec.Args, argTenantID, argTenantIDVal)

			if argEnvironmentVal != "" {
				// environment is optional
				exec.Args = append(exec.Args, argEnvironment, argEnvironmentVal)
			}

			if o.isSet(flagUsername) {
				exec.Args = append(exec.Args, argUsername, o.TokenOptions.Username)
			}

			if o.isSet(flagPassword) {
				exec.Args = append(exec.Args, argPassword, o.TokenOptions.Password)
			}

			if isLegacyConfigMode {
				exec.Args = append(exec.Args, argIsLegacy)
			}

		case token.WorkloadIdentityLogin:

			if o.isSet(flagClientID) {
				exec.Args = append(exec.Args, argClientID, o.TokenOptions.ClientID)
			}

			if o.isSet(flagTenantID) {
				exec.Args = append(exec.Args, argTenantID, o.TokenOptions.TenantID)
			}

			if o.isSet(flagAuthorityHost) {
				exec.Args = append(exec.Args, argAuthorityHost, o.TokenOptions.AuthorityHost)
			}

			if o.isSet(flagFederatedTokenFile) {
				exec.Args = append(exec.Args, argFederatedTokenFile, o.TokenOptions.FederatedTokenFile)
			}
		}

		authInfo.Exec = exec
		authInfo.AuthProvider = nil
	}
	err = clientcmd.ModifyConfig(pathOptions, config, true)
	return err
}

// get the item in Exec.Args[] right after someArg
func getExecArg(authInfoPtr *api.AuthInfo, someArg string) (resultStr string) {
	if someArg == "" {
		return
	}
	if authInfoPtr == nil || authInfoPtr.Exec == nil || authInfoPtr.Exec.Args == nil {
		return
	}
	if len(authInfoPtr.Exec.Args) < 1 {
		return
	}
	for i := range authInfoPtr.Exec.Args {
		if authInfoPtr.Exec.Args[i] == someArg {
			if len(authInfoPtr.Exec.Args) > i+1 {
				return authInfoPtr.Exec.Args[i+1]
			}
		}
	}
	return
}

func getExecBoolArg(authInfoPtr *api.AuthInfo, someArg string) bool {
	if someArg == "" {
		return false
	}
	if authInfoPtr == nil || authInfoPtr.Exec == nil || authInfoPtr.Exec.Args == nil {
		return false
	}
	if len(authInfoPtr.Exec.Args) < 1 {
		return false
	}
	for i := range authInfoPtr.Exec.Args {
		if authInfoPtr.Exec.Args[i] == someArg {
			return true
		}
	}
	return false
}

// If enabling PoP token support, users must provide both "--pop-enabled" and "--pop-claims" flags together.
// If either is provided without the other, validation should throw an error, otherwise the get-token command
// will fail under the hood.
func validatePoPClaims(args []string, isPopTokenEnabled bool, popTokenClaimsFlag, popTokenClaimsVal string) ([]string, error) {
	if isPopTokenEnabled && popTokenClaimsVal == "" {
		// pop-enabled and pop-claims must be provided together
		return args, fmt.Errorf("%s is required when specifying %s", argPoPTokenClaims, argIsPoPTokenEnabled)
	}

	if popTokenClaimsVal != "" && !isPopTokenEnabled {
		// pop-enabled and pop-claims must be provided together
		return args, fmt.Errorf("%s is required when specifying %s", argIsPoPTokenEnabled, argPoPTokenClaims)
	}

	if isPopTokenEnabled && popTokenClaimsVal != "" {
		args = append(args, argIsPoPTokenEnabled)
		args = append(args, popTokenClaimsFlag, popTokenClaimsVal)
	}

	return args, nil
}
07070100000058000081A4000000000000000000000001687816E50000BC42000000000000000000000000000000000000003800000000kubelogin-0.2.10/pkg/internal/converter/convert_test.gopackage converter

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/Azure/kubelogin/pkg/internal/token"
	"github.com/spf13/pflag"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/client-go/tools/clientcmd"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)

func TestConvert(t *testing.T) {
	const (
		clusterName1       = "aks1"
		clusterName2       = "aks2"
		envName            = "foo"
		serverID           = "serverID"
		clientID           = "clientID"
		spClientID         = "spClientID"
		tenantID           = "tenantID"
		clientSecret       = "foosecret"
		clientCert         = "/tmp/clientcert"
		clientCertPassword = "clientcertsecret"
		username           = "foo123"
		password           = "foobar"
		loginMethod        = "devicecode"
		identityResourceID = "/msi/resource/id"
		authorityHost      = "https://login.microsoftonline.com/"
		federatedTokenFile = "/tmp/file"
		authRecordCacheDir = "/tmp/token_dir"
		azureCLIDir        = "/tmp/foo"
		redirectURL        = "http://localhost:8000"
		usernameHint       = "username"
	)
	testData := []struct {
		name                string
		authProviderConfig  map[string]string
		overrideFlags       map[string]string
		expectedArgs        []string
		execArgItems        []string
		command             string
		expectedExecName    string
		installHint         string
		expectedInstallHint string
		expectedError       string
		expectedEnv         []clientcmdapi.ExecEnvVar
	}{
		{
			name: "non azure kubeconfig",
		},
		{
			name:             "non azure kubeconfig in exec format with install hint",
			command:          "foo",
			expectedExecName: "foo",
			execArgItems: []string{
				"--bar",
			},
			expectedArgs: []string{
				"--bar",
			},
			installHint:         "foo install hint",
			expectedInstallHint: "foo install hint",
		},
		{
			name: "using legacy azure auth to convert to msi",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "0",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.MSILogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.MSILogin,
			},
		},
		{
			name: "using legacy azure auth to convert to msi will overwrite install hint",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "0",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.MSILogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.MSILogin,
			},
			installHint: "Overwrite this install hint",
		},
		{
			name: "using legacy azure auth to convert to msi with client-id override",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "0",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.MSILogin,
				flagClientID:    "msi-client-id",
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, "msi-client-id",
				argLoginMethod, token.MSILogin,
			},
		},
		{
			name: "using legacy azure auth to convert to workload identity",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "0",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.WorkloadIdentityLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.WorkloadIdentityLogin,
			},
		},
		{
			name: "using legacy azure auth to convert to workload identity with overrides",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "0",
			},
			overrideFlags: map[string]string{
				flagLoginMethod:        token.WorkloadIdentityLogin,
				flagClientID:           spClientID,
				flagTenantID:           tenantID,
				flagAuthorityHost:      authorityHost,
				flagFederatedTokenFile: federatedTokenFile,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, spClientID,
				argTenantID, tenantID,
				argAuthorityHost, authorityHost,
				argFederatedTokenFile, federatedTokenFile,
				argLoginMethod, token.WorkloadIdentityLogin,
			},
		},
		{
			name: "using legacy azure auth to convert to spn without setting environment",
			authProviderConfig: map[string]string{
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ServicePrincipalLogin,
				flagClientID:    spClientID,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, spClientID,
				argTenantID, tenantID,
				argLoginMethod, token.ServicePrincipalLogin,
			},
		},
		{
			name: "using legacy azure auth to convert to spn with clientSecret",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod:  token.ServicePrincipalLogin,
				flagClientID:     spClientID,
				flagClientSecret: clientSecret,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, spClientID,
				argClientSecret, clientSecret,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.ServicePrincipalLogin,
			},
		},
		{
			name: "using legacy azure auth to convert to spn with clientCert",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ServicePrincipalLogin,
				flagClientID:    spClientID,
				flagClientCert:  clientCert,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, spClientID,
				argClientCert, clientCert,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.ServicePrincipalLogin,
			},
		},
		{
			name: "using legacy azure auth to convert to spn with password-protected clientCert",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod:        token.ServicePrincipalLogin,
				flagClientID:           spClientID,
				flagClientCert:         clientCert,
				flagClientCertPassword: clientCertPassword,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, spClientID,
				argClientCert, clientCert,
				argClientCertPassword, clientCertPassword,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.ServicePrincipalLogin,
			},
		},
		{
			name: "using legacy azure auth to convert to ropc",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ROPCLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.ROPCLogin,
			},
		},
		{
			name: "using legacy azure auth to convert to ropc with username and password",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ROPCLogin,
				flagUsername:    username,
				flagPassword:    password,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argUsername, username,
				argPassword, password,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.ROPCLogin,
			},
		},
		{
			name: "using legacy azure auth to convert to azurecli",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureCLILogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
			},
		},
		{
			name: "using legacy azure auth to convert to azd",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureDeveloperCLILogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureDeveloperCLILogin,
			},
		},
		{
			name: "using legacy azure auth to convert to azurecli with --tenant-id override",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureCLILogin,
				flagTenantID:    tenantID,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
				argTenantID, tenantID,
			},
		},
		{
			name: "using legacy azure auth to convert to azd with --tenant-id override",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureDeveloperCLILogin,
				flagTenantID:    tenantID,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureDeveloperCLILogin,
				argTenantID, tenantID,
			},
		},
		{
			name: "using legacy azure auth to convert to azurecli with --token-cache-dir override",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			overrideFlags: map[string]string{
				flagLoginMethod:   token.AzureCLILogin,
				flagTokenCacheDir: authRecordCacheDir,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
				argAuthRecordCacheDir, authRecordCacheDir,
			},
		},
		{
			name: "using legacy azure auth to convert to devicecode with redundant arguments",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "0",
			},
			overrideFlags: map[string]string{
				flagEnvironment:        envName,
				flagServerID:           serverID,
				flagClientID:           clientID,
				flagTenantID:           tenantID,
				flagClientSecret:       clientSecret,
				flagClientCert:         clientCert,
				flagClientCertPassword: clientCertPassword,
				flagUsername:           username,
				flagPassword:           password,
				flagLoginMethod:        loginMethod,
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argIsLegacy,
				argLoginMethod, loginMethod,
			},
		},
		{
			name: "using legacy azure auth with configMode: \"1\" to convert to devicecode with --legacy",
			authProviderConfig: map[string]string{
				cfgConfigMode: "1",
			},
			overrideFlags: map[string]string{
				flagEnvironment: envName,
				flagServerID:    serverID,
				flagClientID:    clientID,
				flagTenantID:    tenantID,
				flagLoginMethod: loginMethod,
				flagIsLegacy:    "true",
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argIsLegacy,
				argLoginMethod, loginMethod,
			},
		},
		{
			name: "using legacy azure auth to convert without --login should default to devicecode",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argIsLegacy,
				argLoginMethod, token.DeviceCodeLogin,
			},
		},
		{
			name: "using legacy azure auth with configMode: \"0\" to convert without --login should default to devicecode",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "0",
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argIsLegacy,
				argLoginMethod, token.DeviceCodeLogin,
			},
		},
		{
			name: "using legacy azure auth with configMode: \"1\" to convert without --login should result in devicecode without --legacy",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "1",
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.DeviceCodeLogin,
			},
		},
		{
			name: "with exec format kubeconfig, convert from azurecli to azurecli",
			execArgItems: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.AzureCLILogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureCLILogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from azurecli to azurecli with existing install hint",
			execArgItems: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.AzureCLILogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureCLILogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
			},
			command:             execName,
			installHint:         "Preserve this install hint",
			expectedInstallHint: "Preserve this install hint",
		},
		{
			name: "with exec format kubeconfig, convert from azurecli to azurecli with --tenant-id",
			execArgItems: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.AzureCLILogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureCLILogin,
				flagTenantID:    tenantID,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
				argTenantID, tenantID,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from azurecli to azurecli, with envName as overrides",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.AzureCLILogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureCLILogin,
				flagEnvironment: envName,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from azurecli to azurecli, with args as overrides",
			execArgItems: []string{
				getTokenCommand,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureCLILogin,
				flagServerID:    serverID,
				flagClientID:    clientID,
				flagTenantID:    tenantID,
				flagEnvironment: envName,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
				argTenantID, tenantID,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from azurecli to devicecode",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
			},
			overrideFlags: map[string]string{
				flagClientID:    clientID,
				flagTenantID:    tenantID,
				flagLoginMethod: token.DeviceCodeLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.DeviceCodeLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from azurecli to devicecode with existing install hint",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
			},
			overrideFlags: map[string]string{
				flagClientID:    clientID,
				flagTenantID:    tenantID,
				flagLoginMethod: token.DeviceCodeLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.DeviceCodeLogin,
			},
			command:             execName,
			installHint:         "Preserve this install hint",
			expectedInstallHint: "Preserve this install hint",
		},
		{
			name: "with exec format kubeconfig, convert from azurecli to devicecode, with args as overrides",
			execArgItems: []string{
				getTokenCommand,
				argLoginMethod, token.AzureCLILogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.DeviceCodeLogin,
				flagServerID:    serverID,
				flagClientID:    clientID,
				flagTenantID:    tenantID,
				flagEnvironment: envName,
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.DeviceCodeLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to devicecode without override",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to devicecode with --legacy",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagIsLegacy: "true",
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argIsLegacy,
				argLoginMethod, token.DeviceCodeLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig using devicecode and --legacy, convert to devicecode should still have --legacy",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
				argIsLegacy,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.DeviceCodeLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argIsLegacy,
				argLoginMethod, token.DeviceCodeLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to azurecli",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureCLILogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to azurecli with --token-cache-dir override",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod:   token.AzureCLILogin,
				flagTokenCacheDir: authRecordCacheDir,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
				argAuthRecordCacheDir, authRecordCacheDir,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to azurecli with --cache-dir",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
				argAuthRecordCacheDir, authRecordCacheDir,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureCLILogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
				argAuthRecordCacheDir, authRecordCacheDir,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to azurecli with --cache-dir override",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod:        token.AzureCLILogin,
				flagAuthRecordCacheDir: authRecordCacheDir,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
				argAuthRecordCacheDir, authRecordCacheDir,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig already having --token-cache-dir, convert from devicecode to azurecli",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argTokenCacheDir, authRecordCacheDir,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.AzureCLILogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
				argAuthRecordCacheDir, authRecordCacheDir,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to spn",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ServicePrincipalLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argTenantID, tenantID,
				argClientID, clientID,
				argLoginMethod, token.ServicePrincipalLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to spn without setting environment",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ServicePrincipalLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argTenantID, tenantID,
				argClientID, clientID,
				argLoginMethod, token.ServicePrincipalLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to spn with clientID",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ServicePrincipalLogin,
				flagClientID:    spClientID,
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, spClientID,
				argTenantID, tenantID,
				argLoginMethod, token.ServicePrincipalLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to spn with --legacy",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ServicePrincipalLogin,
				flagClientID:    spClientID,
				flagIsLegacy:    "true",
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argClientID, spClientID,
				argTenantID, tenantID,
				argIsLegacy,
				argLoginMethod, token.ServicePrincipalLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to msi",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.MSILogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.MSILogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to msi with clientID override",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.MSILogin,
				flagClientID:    spClientID,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, spClientID,
				argLoginMethod, token.MSILogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to msi with identity-resource-id override",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod:        token.MSILogin,
				flagIdentityResourceID: identityResourceID,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argIdentityResourceID, identityResourceID,
				argLoginMethod, token.MSILogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to ropc",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ROPCLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.ROPCLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to ropc with --legacy",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ROPCLogin,
				flagIsLegacy:    "true",
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argIsLegacy,
				argLoginMethod, token.ROPCLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to ropc with username and password",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.ROPCLogin,
				flagUsername:    username,
				flagPassword:    password,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argUsername, username,
				argPassword, password,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.ROPCLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to workload identity",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.WorkloadIdentityLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.WorkloadIdentityLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to workload identity with override",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod:        token.WorkloadIdentityLogin,
				flagClientID:           spClientID,
				flagTenantID:           tenantID,
				flagAuthorityHost:      authorityHost,
				flagFederatedTokenFile: federatedTokenFile,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, spClientID,
				argTenantID, tenantID,
				argAuthorityHost, authorityHost,
				argFederatedTokenFile, federatedTokenFile,
				argLoginMethod, token.WorkloadIdentityLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to interactive",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.InteractiveLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.InteractiveLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to interactive without setting environment",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.InteractiveLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argTenantID, tenantID,
				argClientID, clientID,
				argLoginMethod, token.InteractiveLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to interactive with override",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.InteractiveLogin,
				flagServerID:    serverID,
				flagClientID:    clientID,
				flagTenantID:    tenantID,
				flagEnvironment: envName,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.InteractiveLogin,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to interactive with redirect url override",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.InteractiveLogin,
				flagServerID:    serverID,
				flagClientID:    clientID,
				flagTenantID:    tenantID,
				flagEnvironment: envName,
				flagRedirectURL: redirectURL,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.InteractiveLogin,
				argRedirectURL, redirectURL,
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to interactive with login hint override",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.InteractiveLogin,
				flagServerID:    serverID,
				flagClientID:    clientID,
				flagTenantID:    tenantID,
				flagEnvironment: envName,
				flagLoginHint:   usernameHint,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.InteractiveLogin,
				argLoginHint, usernameHint,
			},
			command: execName,
		},
		{
			name: "convert with context specified, auth info not specified by the context should not be changed",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "0",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.MSILogin,
				flagContext:     clusterName1,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.MSILogin,
			},
		},
		{
			name: "convert with non-existent context specified, Convert should return error",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "0",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.MSILogin,
				flagContext:     "badContext",
			},
			expectedError: "no context exists with the name: \"badContext\"",
		},
		{
			name: "with --azure-config-dir specified, exec.Env should be set accordingly",
			authProviderConfig: map[string]string{
				cfgEnvironment: envName,
				cfgApiserverID: serverID,
				cfgClientID:    clientID,
				cfgTenantID:    tenantID,
				cfgConfigMode:  "0",
			},
			overrideFlags: map[string]string{
				flagLoginMethod:    token.AzureCLILogin,
				flagContext:        clusterName1,
				flagAzureConfigDir: azureCLIDir,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
			},
			expectedEnv: []clientcmdapi.ExecEnvVar{
				{
					Name:  azureConfigDir,
					Value: azureCLIDir,
				},
			},
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to interactive with only pop-enabled specified, Convert should return error",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
				argIsPoPTokenEnabled,
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.InteractiveLogin,
			},
			command:       execName,
			expectedError: "--pop-claims is required when specifying --pop-enabled",
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to interactive with only pop-claims specified, Convert should return error",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
				argPoPTokenClaims, "u=testhost",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.InteractiveLogin,
			},
			command:       execName,
			expectedError: "--pop-enabled is required when specifying --pop-claims",
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to interactive with pop-enabled and pop-claims",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
				argIsPoPTokenEnabled,
				argPoPTokenClaims, "u=testhost, 1=2",
			},
			overrideFlags: map[string]string{
				flagLoginMethod: token.InteractiveLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.InteractiveLogin,
				argIsPoPTokenEnabled,
				argPoPTokenClaims, "u=testhost, 1=2",
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from devicecode to spn with pop-enabled and pop-claims as flags",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod:       token.ServicePrincipalLogin,
				flagIsPoPTokenEnabled: "true",
				flagPoPTokenClaims:    "u=testhost, 1=2",
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argTenantID, tenantID,
				argClientID, clientID,
				argLoginMethod, token.ServicePrincipalLogin,
				argIsPoPTokenEnabled,
				argPoPTokenClaims, "u=testhost, 1=2",
			},
			command: execName,
		},
		{
			name: "with exec format kubeconfig, convert from azurecli to devicecode with pop-enabled and pop-claims, expect pop args to be ignored",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argLoginMethod, token.AzureCLILogin,
				argIsPoPTokenEnabled,
				argPoPTokenClaims, "u=testhost, 1=2",
			},
			overrideFlags: map[string]string{
				flagClientID:    clientID,
				flagTenantID:    tenantID,
				flagLoginMethod: token.DeviceCodeLogin,
			},
			expectedArgs: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argLoginMethod, token.DeviceCodeLogin,
			},
			command: execName,
		},
		{
			name: "test with exec format kubeconfig, convert from devicecode to spn with environment override flag disabled.",
			execArgItems: []string{
				getTokenCommand,
				argServerID, serverID,
				argClientID, clientID,
				argTenantID, tenantID,
				argEnvironment, envName,
				argLoginMethod, token.DeviceCodeLogin,
			},
			overrideFlags: map[string]string{
				flagLoginMethod:                token.ServicePrincipalLogin,
				flagDisableEnvironmentOverride: "true",
			},
			expectedArgs: []string{
				getTokenCommand,
				argEnvironment, envName,
				argServerID, serverID,
				argTenantID, tenantID,
				argClientID, clientID,
				argLoginMethod, token.ServicePrincipalLogin,
				argDisableEnvironmentOverride,
			},
			command: execName,
		},
	}
	rootTmpDir, err := os.MkdirTemp("", "kubelogin-test")
	if err != nil {
		t.Fatalf("unable to create temp dir: %s", err)
	}
	defer os.RemoveAll(rootTmpDir)
	for _, data := range testData {
		t.Run(data.name, func(t *testing.T) {
			var authProviderName string
			tmpDir, err := os.MkdirTemp(rootTmpDir, "config")
			if err != nil {
				t.Fatalf("%s", err)
			}
			if data.expectedArgs != nil {
				authProviderName = azureAuthProvider
			}
			kubeconfigFile := filepath.Join(tmpDir, "config")

			config := createValidTestConfigs(
				clusterName1,
				clusterName2,
				data.command,
				authProviderName,
				data.authProviderConfig,
				data.execArgItems,
				data.installHint,
			)
			fs := &pflag.FlagSet{}
			o := Options{
				Flags: fs,
				configFlags: genericclioptions.NewTestConfigFlags().
					WithClientConfig(clientcmd.NewNonInteractiveClientConfig(*config, clusterName1, &clientcmd.ConfigOverrides{}, nil)),
			}
			o.AddFlags(fs)

			for k, v := range data.overrideFlags {
				if err := o.setFlag(k, v); err != nil {
					t.Fatalf("unable to add flag: %s, err: %s", k, err)
				}
			}

			pathOptions := clientcmd.PathOptions{
				ExplicitFileFlag: "kubeconfig",
				LoadingRules: &clientcmd.ClientConfigLoadingRules{
					ExplicitPath: kubeconfigFile,
				},
			}
			err = Convert(o, &pathOptions)
			if data.expectedError == "" && err != nil {
				t.Fatalf("Unexpected error from Convert: %v", err)
			} else if data.expectedError != "" {
				if err == nil || err.Error() != data.expectedError {
					t.Fatalf("Expected error: %q, but got: %q", data.expectedError, err)
				}
			} else {
				// only need to validate fields if we're not expecting an error
				if o.context != "" {
					// when --context is specified, convert-kubeconfig will convert only the targeted context
					// hence, we expect the second auth info not to change
					validate(t, clusterName1, config.AuthInfos[clusterName1], data.expectedArgs, data.expectedExecName, data.expectedInstallHint, data.expectedEnv)
					validateAuthInfoThatShouldNotChange(t, clusterName2, config.AuthInfos[clusterName2], data.authProviderConfig)
				} else {
					// when --context is not specified, convert-kubeconfig will convert every auth info in the kubeconfig
					// hence, we expect the second auth info to be converted in the same way as the first one
					validate(t, clusterName1, config.AuthInfos[clusterName1], data.expectedArgs, data.expectedExecName, data.expectedInstallHint, data.expectedEnv)
					validate(t, clusterName2, config.AuthInfos[clusterName2], data.expectedArgs, data.expectedExecName, data.expectedInstallHint, data.expectedEnv)
				}
			}
		})
	}
}

func createValidTestConfigs(
	name1, name2, commandName, authProviderName string,
	authProviderConfig map[string]string,
	execArgItems []string,
	installHint string,
) *clientcmdapi.Config {
	const server = "https://anything.com:8080"

	config := clientcmdapi.NewConfig()
	for _, name := range []string{name1, name2} {
		config.Clusters[name] = &clientcmdapi.Cluster{
			Server: server,
		}

		if authProviderConfig == nil && execArgItems != nil {
			config.AuthInfos[name] = &clientcmdapi.AuthInfo{
				Exec: &clientcmdapi.ExecConfig{
					Args:        execArgItems,
					Command:     commandName,
					InstallHint: installHint,
				},
			}
		} else {
			config.AuthInfos[name] = &clientcmdapi.AuthInfo{
				AuthProvider: &clientcmdapi.AuthProviderConfig{
					Name:   authProviderName,
					Config: authProviderConfig,
				},
			}
		}

		config.Contexts[name] = &clientcmdapi.Context{
			Cluster:  name,
			AuthInfo: name,
		}
	}
	config.CurrentContext = name1

	return config
}

func validate(
	t *testing.T,
	clusterName string,
	authInfo *clientcmdapi.AuthInfo,
	expectedArgs []string,
	expectedExecName string,
	expectedInstallHint string,
	expectedEnv []clientcmdapi.ExecEnvVar,
) {
	if expectedArgs == nil {
		if authInfo.AuthProvider == nil {
			t.Fatalf("[context:%s]: %s", clusterName, "auth provider should not be reset")
		}
		if authInfo.Exec != nil {
			t.Fatalf("[context:%s]: %s", clusterName, "plugin should not be set")
		}
		return
	}

	if authInfo.AuthProvider != nil {
		t.Fatalf("[context:%s]: %s", clusterName, "auth provider should be reset")
	}
	exec := authInfo.Exec
	if exec == nil {
		t.Fatalf("[context:%s]: %s", clusterName, "unable to find exec plugin")
	}

	// default to the kubelogin exec name
	if expectedExecName == "" {
		expectedExecName = execName
	}

	if exec.Command != expectedExecName {
		t.Fatalf("[context:%s]: expected exec command: %s, actual: %s", clusterName, expectedExecName, exec.Command)
	}

	// default to the kubelogin install hint
	if expectedInstallHint == "" {
		expectedInstallHint = execInstallHint
	}

	if exec.InstallHint != expectedInstallHint {
		t.Fatalf("[context:%s]: expected install hint: %s, actual: %s", clusterName, expectedInstallHint, exec.InstallHint)
	}

	// Only validate the API version and first arg if exec is using kubelogin
	if exec.Command == execName {
		if exec.APIVersion != execAPIVersion {
			t.Fatalf("[context:%s]: expected API Version: %s, actual: %s", clusterName, execAPIVersion, exec.APIVersion)
		}

		if exec.Args[0] != getTokenCommand {
			t.Fatalf("[context:%s]: expected %s as first argument. actual: %s", clusterName, getTokenCommand, exec.Args[0])
		}
	}

	if len(exec.Args) != len(expectedArgs) {
		t.Fatalf("[context:%s]: expected exec args: %v, actual: %v", clusterName, expectedArgs, exec.Args)
	}
	for _, v := range expectedArgs {
		if !contains(exec.Args, v) {
			t.Fatalf("[context:%s]: expected exec arg: %s not found in %v", clusterName, v, exec.Args)
		}
	}
	if len(expectedEnv) != len(exec.Env) {
		t.Fatalf("[context:%s]: expected Env has %d entries, got %d", clusterName, len(expectedEnv), len(exec.Env))
	}
	for i, v := range expectedEnv {
		if exec.Env[i] != v {
			t.Fatalf("[context:%s]: for exec.Env, expected %q at index %d, got %q", clusterName, v, i, exec.Env[i])
		}
	}
}

func validateAuthInfoThatShouldNotChange(
	t *testing.T,
	clusterName string,
	authInfo *clientcmdapi.AuthInfo,
	authProviderConfig map[string]string,
) {
	if authInfo.AuthProvider == nil {
		t.Fatalf("[context:%s]: %s", clusterName, "auth provider should not be reset")
	}
	for k, v := range authInfo.AuthProvider.Config {
		if authProviderConfig[k] != v {
			t.Fatalf("[context:%s]: %s=%s does not match with input %s=%s", clusterName, k, v, k, authProviderConfig[k])
		}
	}
	for k, v := range authProviderConfig {
		if authInfo.AuthProvider.Config[k] != v {
			t.Fatalf("[context:%s]: %s=%s does not match with output %s=%s", clusterName, k, v, k, authInfo.AuthProvider.Config[k])
		}
	}
}

func (o *Options) setFlag(key, value string) error {
	return o.Flags.Set(key, value)
}

func contains(a []string, x string) bool {
	for _, n := range a {
		if x == n {
			return true
		}
	}
	return false
}
07070100000059000081A4000000000000000000000001687816E500000A3A000000000000000000000000000000000000003300000000kubelogin-0.2.10/pkg/internal/converter/options.gopackage converter

import (
	"fmt"

	"github.com/Azure/kubelogin/pkg/internal/token"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"k8s.io/cli-runtime/pkg/genericclioptions"
)

type Options struct {
	Flags        *pflag.FlagSet
	configFlags  genericclioptions.RESTClientGetter
	TokenOptions token.Options
	// context is the kubeconfig context name
	context        string
	azureConfigDir string
}

func stringptr(str string) *string { return &str }

func New() Options {
	configFlags := &genericclioptions.ConfigFlags{
		KubeConfig: stringptr(""),
	}
	return Options{configFlags: configFlags}
}

func (o *Options) AddFlags(fs *pflag.FlagSet) {
	o.TokenOptions = token.NewOptions(true)
	if cf, ok := o.configFlags.(*genericclioptions.ConfigFlags); ok {
		cf.AddFlags(fs)
	}
	fs.StringVar(&o.context, flagContext, "", "The name of the kubeconfig context to use")
	fs.StringVar(&o.azureConfigDir, flagAzureConfigDir, "", "Azure CLI config path")
	o.TokenOptions.AddFlags(fs)
}

func (o *Options) Validate() error {
	return o.TokenOptions.Validate()
}

func (o *Options) UpdateFromEnv() {
	o.TokenOptions.UpdateFromEnv()
}

func (o *Options) ToString() string {
	return fmt.Sprintf("Context: %s, %s", o.context, o.TokenOptions.ToString())
}

func (o *Options) isSet(name string) bool {
	found := false
	o.Flags.Visit(func(f *pflag.Flag) {
		if f.Name == name {
			found = true
		}
	})
	return found
}

func (o *Options) AddCompletions(cmd *cobra.Command) {
	_ = cmd.RegisterFlagCompletionFunc(flagContext, completeContexts(o))
	_ = cmd.MarkFlagDirname(flagAzureConfigDir)
	_ = cmd.MarkFlagFilename("kubeconfig", "")

	o.TokenOptions.AddCompletions(cmd)

	cmd.Flags().VisitAll(func(flag *pflag.Flag) {
		// Set a default completion function if none was set. We don't look
		// up if it does already have one set, because Cobra does this for
		// us, and returns an error (which we ignore for this reason).
		_ = cmd.RegisterFlagCompletionFunc(flag.Name, cobra.NoFileCompletions)
	})
}

func completeContexts(o *Options) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
	return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
		clientConfig := o.configFlags.ToRawKubeConfigLoader()
		config, err := clientConfig.RawConfig()
		if err != nil {
			cobra.CompDebugln(fmt.Sprintf("unable to load kubeconfig: %s", err), false)
		}

		contexts := make([]string, 0, len(config.Contexts))
		for name := range config.Contexts {
			contexts = append(contexts, name)
		}

		return contexts, cobra.ShellCompDirectiveNoFileComp
	}
}
0707010000005A000081A4000000000000000000000001687816E500000125000000000000000000000000000000000000003800000000kubelogin-0.2.10/pkg/internal/converter/options_test.gopackage converter

import (
	"testing"

	"github.com/spf13/pflag"
)

func TestOptions(t *testing.T) {
	o := New()
	o.AddFlags(&pflag.FlagSet{})
	o.UpdateFromEnv()
	o.TokenOptions.ServerID = "server-id"
	if err := o.Validate(); err != nil {
		t.Fatalf("option validation failed: %s", err)
	}
}
0707010000005B000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002200000000kubelogin-0.2.10/pkg/internal/env0707010000005C000081A4000000000000000000000001687816E5000005AC000000000000000000000000000000000000002F00000000kubelogin-0.2.10/pkg/internal/env/variables.gopackage env

const (
	// env vars
	LoginMethod                        = "AAD_LOGIN_METHOD"
	KubeloginROPCUsername              = "AAD_USER_PRINCIPAL_NAME"
	KubeloginROPCPassword              = "AAD_USER_PRINCIPAL_PASSWORD"
	KubeloginClientID                  = "AAD_SERVICE_PRINCIPAL_CLIENT_ID"
	KubeloginClientSecret              = "AAD_SERVICE_PRINCIPAL_CLIENT_SECRET"
	KubeloginClientCertificatePath     = "AAD_SERVICE_PRINCIPAL_CLIENT_CERTIFICATE"
	KubeloginClientCertificatePassword = "AAD_SERVICE_PRINCIPAL_CLIENT_CERTIFICATE_PASSWORD"

	// env vars used by Terraform
	TerraformClientID                  = "ARM_CLIENT_ID"
	TerraformClientSecret              = "ARM_CLIENT_SECRET"
	TerraformClientCertificatePath     = "ARM_CLIENT_CERTIFICATE_PATH"
	TerraformClientCertificatePassword = "ARM_CLIENT_CERTIFICATE_PASSWORD"
	TerraformTenantID                  = "ARM_TENANT_ID"

	// env vars following azure sdk naming convention
	AzureAuthorityHost             = "AZURE_AUTHORITY_HOST"
	AzureClientCertificatePassword = "AZURE_CLIENT_CERTIFICATE_PASSWORD"
	AzureClientCertificatePath     = "AZURE_CLIENT_CERTIFICATE_PATH"
	AzureClientID                  = "AZURE_CLIENT_ID"
	AzureClientSecret              = "AZURE_CLIENT_SECRET"
	AzureFederatedTokenFile        = "AZURE_FEDERATED_TOKEN_FILE"
	AzureTenantID                  = "AZURE_TENANT_ID"
	AzureUsername                  = "AZURE_USERNAME"
	AzurePassword                  = "AZURE_PASSWORD"
)
0707010000005D000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002200000000kubelogin-0.2.10/pkg/internal/pop0707010000005E000081A4000000000000000000000001687816E5000011ED000000000000000000000000000000000000003100000000kubelogin-0.2.10/pkg/internal/pop/authnscheme.go// Disclaimer: The PoPAuthenticationScheme implementation of the MSAL AuthenticationScheme
// interface is intended for the usage of Azure Arc.

package pop

import (
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"strings"
	"time"

	"github.com/google/uuid"
)

// type of a PoP token, as opposed to "JWT" for a regular bearer token
const popTokenType = "pop"

// PoPAuthenticationScheme is a PoP token implementation of the MSAL AuthenticationScheme interface
// used by the Azure Arc Platform team.
// This implementation will only use the passed-in u-claim (representing the ARM ID of the
// cluster/host); other claims passed in during a PoP token request will be disregarded
type PoPAuthenticationScheme struct {
	// host is the u claim we will add on the pop token
	Host   string
	PoPKey PoPKey
}

// TokenRequestParams returns the params to use when sending a request for a PoP token
func (as *PoPAuthenticationScheme) TokenRequestParams() map[string]string {
	return map[string]string{
		"token_type": popTokenType,
		"req_cnf":    as.PoPKey.ReqCnf(),
	}
}

// KeyID returns the key used to sign the PoP token
func (as *PoPAuthenticationScheme) KeyID() string {
	return as.PoPKey.KeyID()
}

// FormatAccessToken takes an access token, formats it as a PoP token,
// and returns it as a base-64 encoded string
func (as *PoPAuthenticationScheme) FormatAccessToken(accessToken string) (string, error) {
	timestamp := time.Now().Unix()
	nonce := uuid.NewString()
	nonce = strings.ReplaceAll(nonce, "-", "")

	return as.FormatAccessTokenWithOptions(accessToken, nonce, timestamp)
}

// FormatAccessTokenWithOptions takes an access token, nonce, and timestamp, formats
// the token as a PoP token containing the given fields, and returns it as a
// base-64 encoded string
func (as *PoPAuthenticationScheme) FormatAccessTokenWithOptions(accessToken, nonce string, timestamp int64) (string, error) {
	header := header{
		typ: popTokenType,
		alg: as.PoPKey.Alg(),
		kid: as.PoPKey.KeyID(),
	}
	payload := payload{
		at:    accessToken,
		ts:    timestamp,
		host:  as.Host,
		jwk:   as.PoPKey.JWK(),
		nonce: nonce,
	}

	popAccessToken, err := createPoPAccessToken(header, payload, as.PoPKey)
	if err != nil {
		return "", fmt.Errorf("error formatting PoP token: %w", err)
	}
	return popAccessToken.ToBase64(), nil
}

// AccessTokenType returns the PoP access token type
func (as *PoPAuthenticationScheme) AccessTokenType() string {
	return popTokenType
}

// type representing the header of a PoP access token
type header struct {
	typ string
	alg string
	kid string
}

// ToString returns a string representation of a header object
func (h *header) ToString() string {
	return fmt.Sprintf(`{"typ":"%s","alg":"%s","kid":"%s"}`, h.typ, h.alg, h.kid)
}

// ToBase64 returns a base-64 encoded string representation of a header object
func (h *header) ToBase64() string {
	return base64.RawURLEncoding.EncodeToString([]byte(h.ToString()))
}

// type representing the payload of a PoP token
type payload struct {
	at    string
	ts    int64
	host  string
	jwk   string
	nonce string
}

// ToString returns a string representation of a payload object
func (p *payload) ToString() string {
	return fmt.Sprintf(`{"at":"%s","ts":%d,"u":"%s","cnf":{"jwk":%s},"nonce":"%s"}`, p.at, p.ts, p.host, p.jwk, p.nonce)
}

// ToBase64 returns a base-64 encoded representation of a payload object
func (p *payload) ToBase64() string {
	return base64.RawURLEncoding.EncodeToString([]byte(p.ToString()))
}

// type representing the signature of a PoP token
type signature struct {
	sig []byte
}

// ToBase64 returns a base-64 encoded representation of a signature object
func (s *signature) ToBase64() string {
	return base64.RawURLEncoding.EncodeToString(s.sig)
}

// type representing a PoP access token
type popAccessToken struct {
	Header    header
	Payload   payload
	Signature signature
}

// given a header, payload, and PoP key, creates the signature for the token and returns
// a PoPAccessToken object representing the signed token
func createPoPAccessToken(h header, p payload, popKey PoPKey) (*popAccessToken, error) {
	token := &popAccessToken{
		Header:  h,
		Payload: p,
	}
	h256 := sha256.Sum256([]byte(h.ToBase64() + "." + p.ToBase64()))
	sig, err := popKey.Sign(h256[:])
	if err != nil {
		return nil, err
	}
	token.Signature = signature{
		sig: sig,
	}
	return token, nil
}

// ToBase64 returns a base-64 encoded representation of a PoP access token
func (p *popAccessToken) ToBase64() string {
	return fmt.Sprintf("%s.%s.%s", p.Header.ToBase64(), p.Payload.ToBase64(), p.Signature.ToBase64())
}
0707010000005F000081A4000000000000000000000001687816E500000F73000000000000000000000000000000000000003600000000kubelogin-0.2.10/pkg/internal/pop/authnscheme_test.gopackage pop

import (
	"crypto/rand"
	"crypto/rsa"
	"math"
	"strings"
	"testing"
	"time"

	"github.com/golang-jwt/jwt/v4"
	"github.com/google/uuid"
)

func TestAuthnScheme(t *testing.T) {
	t.Run("FormatAccessTokenWithOptions should return a correctly formatted PoP token", func(t *testing.T) {
		accessToken := uuid.NewString()
		timestamp := time.Now().Unix()
		nonce := uuid.NewString()
		nonce = strings.ReplaceAll(nonce, "-", "")
		host := "testresource"
		popKey, err := GetSwPoPKey()
		if err != nil {
			t.Errorf("expected no error but got: %s", err)
		}
		authnScheme := &PoPAuthenticationScheme{
			Host:   host,
			PoPKey: popKey,
		}

		formatted, err := authnScheme.FormatAccessTokenWithOptions(accessToken, nonce, timestamp)
		if err != nil {
			t.Errorf("expected no error but got: %s", err)
		}
		claims := jwt.MapClaims{}
		parsed, _ := jwt.ParseWithClaims(formatted, &claims, func(token *jwt.Token) (interface{}, error) {
			return authnScheme.PoPKey.KeyID(), nil
		})
		if claims["at"] != accessToken {
			t.Errorf("expected access token: %s but got: %s", accessToken, claims["at"])
		}
		if claims["u"] != host {
			t.Errorf("expected u-claim value: %s but got: %s", host, claims["u"])
		}
		ts := int64(math.Round(claims["ts"].(float64)))
		if ts != timestamp {
			t.Errorf("expected timestamp value: %d but got: %d", timestamp, ts)
		}
		if claims["nonce"] != nonce {
			t.Errorf("expected nonce value: %s but got: %s", nonce, claims["nonce"])
		}
		if parsed.Header["typ"] != popTokenType {
			t.Errorf("expected token type: %s but got: %s", popTokenType, parsed.Header["typ"])
		}
		if parsed.Header["alg"] != authnScheme.PoPKey.Alg() {
			t.Errorf("expected token alg: %s but got: %s", authnScheme.PoPKey.Alg(), parsed.Header["alg"])
		}
		if parsed.Header["kid"] != authnScheme.KeyID() {
			t.Errorf("expected token kid: %s but got: %s", authnScheme.PoPKey.KeyID(), parsed.Header["kid"])
		}

		header := header{
			typ: popTokenType,
			alg: authnScheme.PoPKey.Alg(),
			kid: authnScheme.PoPKey.KeyID(),
		}
		payload := payload{
			at:    accessToken,
			ts:    timestamp,
			host:  host,
			jwk:   authnScheme.PoPKey.JWK(),
			nonce: nonce,
		}
		popAccessToken, err := createPoPAccessToken(header, payload, authnScheme.PoPKey)
		if err != nil {
			t.Errorf("expected no error but got: %s", err)
		}
		if parsed.Signature != popAccessToken.Signature.ToBase64() {
			t.Errorf("expected token signature: %s but got: %s", popAccessToken.Signature.ToBase64(), parsed.Signature)
		}
	})

	t.Run("TokenRequestParams should return correct token_type and req_cnf claims", func(t *testing.T) {
		host := "testresource"
		rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
		if err != nil {
			t.Errorf("expected no error generating RSA key but got: %s", err)
		}
		popKey, err := GetSwPoPKeyWithRSAKey(rsaKey)
		if err != nil {
			t.Errorf("expected no error but got: %s", err)
		}
		authnScheme := &PoPAuthenticationScheme{
			Host:   host,
			PoPKey: popKey,
		}
		tokenRequestParams := authnScheme.TokenRequestParams()

		// validate token type
		if tokenRequestParams["token_type"] != "pop" {
			t.Errorf("expected req_cnf: %s but got: %s", "pop", tokenRequestParams["token_type"])
		}

		// validate req_cnf
		eB64, nB64 := getRSAKeyExponentAndModulus(popKey.key)
		jwktp := computeJWKThumbprint(eB64, nB64)
		expectedReqCnf := getReqCnf(jwktp)
		if tokenRequestParams["req_cnf"] != expectedReqCnf {
			t.Errorf("expected req_cnf: %s but got: %s", expectedReqCnf, tokenRequestParams["req_cnf"])
		}
	})

	t.Run("AccessTokenType should return correct type", func(t *testing.T) {
		host := "testresource"
		popKey, err := GetSwPoPKey()
		if err != nil {
			t.Errorf("expected no error but got: %s", err)
		}
		authnScheme := &PoPAuthenticationScheme{
			Host:   host,
			PoPKey: popKey,
		}

		if authnScheme.AccessTokenType() != "pop" {
			t.Errorf("expected req_cnf: %s but got: %s", "pop", authnScheme.AccessTokenType())
		}
	})
}
07070100000060000081A4000000000000000000000001687816E500000DFC000000000000000000000000000000000000003700000000kubelogin-0.2.10/pkg/internal/pop/msal_confidential.gopackage pop

import (
	"context"
	"fmt"
	"net/http"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache"
	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
)

type MsalClientOptions struct {
	Authority                string
	ClientID                 string
	TenantID                 string
	DisableInstanceDiscovery bool
	Options                  azcore.ClientOptions
}

// ClientOptions holds options for creating a confidential client
type ClientOptions struct {
	Cache cache.ExportReplace
}

// ConfidentialClientOption defines a functional option for configuring a confidential client
type ConfidentialClientOption func(*ClientOptions)

// WithCustomCache adds a custom cache to the confidential client
func WithCustomCache(cache cache.ExportReplace) ConfidentialClientOption {
	return func(opts *ClientOptions) {
		opts.Cache = cache
	}
}

// NewConfidentialClient creates a new confidential client with default options
func NewConfidentialClient(
	cred confidential.Credential,
	msalOptions *MsalClientOptions,
	options ...ConfidentialClientOption,
) (confidential.Client, error) {
	if msalOptions == nil {
		return confidential.Client{}, fmt.Errorf("unable to create confidential client: msalClientOptions is empty")
	}

	// Apply custom options
	clientOpts := &ClientOptions{}
	for _, option := range options {
		option(clientOpts)
	}

	// Build confidential options
	var confOptions []confidential.Option
	confOptions = append(confOptions,
		confidential.WithX5C(),
		confidential.WithInstanceDiscovery(!msalOptions.DisableInstanceDiscovery),
	)

	// Add HTTP client if present in msalOptions
	if msalOptions.Options.Transport != nil {
		confOptions = append(confOptions,
			confidential.WithHTTPClient(msalOptions.Options.Transport.(*http.Client)),
		)
	}

	// Add cache if specified
	if clientOpts.Cache != nil {
		confOptions = append(confOptions, confidential.WithCache(clientOpts.Cache))
	}

	client, err := confidential.New(
		msalOptions.Authority,
		msalOptions.ClientID,
		cred,
		confOptions...,
	)

	if err != nil {
		return confidential.Client{}, fmt.Errorf("unable to create confidential client: %w", err)
	}

	return client, nil
}

// AcquirePoPTokenConfidential acquires a PoP token using MSAL's confidential login flow.
// This flow does not require user interaction as the credentials for the request have
// already been provided
// instanceDisovery is to be false only in disconnected clouds to disable instance discovery and authoority validation
func AcquirePoPTokenConfidential(
	context context.Context,
	popClaims map[string]string,
	scopes []string,
	client confidential.Client,
	tenantID string,
	popKeyFunc func() (*SwKey, error),
) (string, int64, error) {
	if popKeyFunc == nil {
		popKeyFunc = GetSwPoPKey
	}
	popKey, err := popKeyFunc()
	if err != nil {
		return "", -1, fmt.Errorf("unable to get PoP key: %w", err)
	}

	authnScheme := &PoPAuthenticationScheme{
		Host:   popClaims["u"],
		PoPKey: popKey,
	}

	result, err := client.AcquireTokenSilent(
		context,
		scopes,
		confidential.WithAuthenticationScheme(authnScheme),
		confidential.WithTenantID(tenantID),
	)
	if err != nil {
		result, err = client.AcquireTokenByCredential(
			context,
			scopes,
			confidential.WithAuthenticationScheme(authnScheme),
			confidential.WithTenantID(tenantID),
		)
		if err != nil {
			return "", -1, fmt.Errorf("failed to create service principal PoP token using secret: %w", err)
		}
	}

	return result.AccessToken, result.ExpiresOn.Unix(), nil
}
07070100000061000081A4000000000000000000000001687816E500001159000000000000000000000000000000000000003C00000000kubelogin-0.2.10/pkg/internal/pop/msal_confidential_test.gopackage pop

import (
	"context"
	"fmt"
	"os"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
	"github.com/Azure/kubelogin/pkg/internal/testutils"
	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
	"github.com/golang-jwt/jwt/v4"
)

type confidentialTokenVars struct {
	clientID     string
	clientSecret string
	resourceID   string
	tenantID     string
	cloud        cloud.Configuration
	popClaims    map[string]string
}

func TestAcquirePoPTokenConfidential(t *testing.T) {
	pEnv := &confidentialTokenVars{
		clientID:     os.Getenv(testutils.ClientID),
		clientSecret: os.Getenv(testutils.ClientSecret),
		resourceID:   os.Getenv(testutils.ResourceID),
		tenantID:     os.Getenv(testutils.TenantID),
	}
	// Use defaults if environmental variables are empty
	if pEnv.clientID == "" {
		pEnv.clientID = testutils.TestClientID
	}
	if pEnv.clientSecret == "" {
		pEnv.clientSecret = testutils.ClientSecret
	}
	if pEnv.resourceID == "" {
		pEnv.resourceID = testutils.TestServerID
	}
	if pEnv.tenantID == "" {
		pEnv.tenantID = testutils.TestTenantID
	}
	ctx := context.Background()
	scopes := []string{pEnv.resourceID + "/.default"}
	authority := "https://login.microsoftonline.com/" + pEnv.tenantID
	var expectedToken string
	var token string
	expectedTokenType := "pop"
	testCase := []struct {
		cassetteName  string
		p             *confidentialTokenVars
		expectedError error
		useSecret     bool
	}{
		{
			// Test using bad client secret
			cassetteName: "AcquirePoPTokenConfidentialFromBadSecretVCR",
			p: &confidentialTokenVars{
				clientID:     pEnv.clientID,
				clientSecret: testutils.BadSecret,
				resourceID:   pEnv.resourceID,
				tenantID:     pEnv.tenantID,
				popClaims:    map[string]string{"u": "testhost"},
				cloud: cloud.Configuration{
					ActiveDirectoryAuthorityHost: authority,
				},
			},
			expectedError: fmt.Errorf("failed to create service principal PoP token using secret"),
			useSecret:     true,
		},
		{
			// Test using service principal secret value to get PoP token
			cassetteName: "AcquirePoPTokenConfidentialWithSecretVCR",
			p: &confidentialTokenVars{
				clientID:     pEnv.clientID,
				clientSecret: pEnv.clientSecret,
				resourceID:   pEnv.resourceID,
				tenantID:     pEnv.tenantID,
				popClaims:    map[string]string{"u": "testhost"},
				cloud: cloud.Configuration{
					ActiveDirectoryAuthorityHost: authority,
				},
			},
			expectedError: nil,
			useSecret:     true,
		},
	}

	for _, tc := range testCase {
		t.Run(tc.cassetteName, func(t *testing.T) {
			if tc.expectedError == nil {
				expectedToken = testutils.TestToken
			}
			vcrRecorder, err := testutils.GetVCRHttpClient(fmt.Sprintf("testdata/%s", tc.cassetteName), pEnv.tenantID)
			if err != nil {
				t.Fatalf("failed to create vcr recorder: %s", err)
			}

			cred, err := confidential.NewCredFromSecret(tc.p.clientSecret)
			if err != nil {
				t.Errorf("expected no error creating credential but got: %s", err)
			}

			MsalClientOptions := &MsalClientOptions{
				Authority: authority,
				ClientID:  tc.p.clientID,
				TenantID:  tc.p.tenantID,
				Options: azcore.ClientOptions{
					Cloud:     cloud.AzurePublic,
					Transport: vcrRecorder.GetDefaultClient(),
				},
				DisableInstanceDiscovery: false,
			}

			client, err := NewConfidentialClient(cred, MsalClientOptions)
			if err != nil {
				t.Errorf("expected no error creating client but got: %s", err)
			}

			token, _, err = AcquirePoPTokenConfidential(
				ctx,
				tc.p.popClaims,
				scopes,
				client,
				tc.p.tenantID,
				GetSwPoPKey,
			)
			defer vcrRecorder.Stop()
			if tc.expectedError != nil {
				if !testutils.ErrorContains(err, tc.expectedError.Error()) {
					t.Errorf("expected error %s, but got %s", tc.expectedError.Error(), err)
				}
			} else if err != nil {
				t.Errorf("expected no error, but got: %s", err)
			} else {
				if token == "" {
					t.Error("expected valid token, but received empty token.")
				}
				claims := jwt.MapClaims{}
				parsed, _ := jwt.ParseWithClaims(token, &claims, nil)
				if claims["at"] != expectedToken {
					t.Errorf("unexpected token returned (expected %s, but got %s)", expectedToken, claims["at"])
				}
				if parsed.Header["typ"] != expectedTokenType {
					t.Errorf("unexpected token returned (expected %s, but got %s)", expectedTokenType, parsed.Header["typ"])
				}
			}
		})
	}
}
07070100000062000081A4000000000000000000000001687816E500000BD0000000000000000000000000000000000000003100000000kubelogin-0.2.10/pkg/internal/pop/msal_public.gopackage pop

import (
	"context"
	"fmt"
	"net/http"

	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/public"
)

// AcquirePoPTokenInteractive acquires a PoP token using MSAL's interactive login flow.
// Requires user to authenticate via browser
func AcquirePoPTokenInteractive(
	context context.Context,
	popClaims map[string]string,
	scopes []string,
	msalOptions *MsalClientOptions,
) (string, int64, error) {
	var client *public.Client
	var err error
	client, err = getPublicClient(msalOptions)
	if err != nil {
		return "", -1, err
	}

	popKey, err := GetSwPoPKey()
	if err != nil {
		return "", -1, err
	}
	result, err := client.AcquireTokenInteractive(
		context,
		scopes,
		public.WithAuthenticationScheme(
			&PoPAuthenticationScheme{
				Host:   popClaims["u"],
				PoPKey: popKey,
			},
		),
		public.WithTenantID(msalOptions.TenantID),
	)
	if err != nil {
		return "", -1, fmt.Errorf("failed to create PoP token with interactive flow: %w", err)
	}

	return result.AccessToken, result.ExpiresOn.Unix(), nil
}

// AcquirePoPTokenByUsernamePassword acquires a PoP token using MSAL's username/password login flow
// This flow does not require user interaction as credentials have already been provided
func AcquirePoPTokenByUsernamePassword(
	context context.Context,
	popClaims map[string]string,
	scopes []string,
	username,
	password string,
	msalOptions *MsalClientOptions,
) (string, int64, error) {
	client, err := getPublicClient(msalOptions)
	if err != nil {
		return "", -1, err
	}

	popKey, err := GetSwPoPKey()
	if err != nil {
		return "", -1, err
	}
	result, err := client.AcquireTokenByUsernamePassword(
		context,
		scopes,
		username,
		password,
		public.WithAuthenticationScheme(
			&PoPAuthenticationScheme{
				Host:   popClaims["u"],
				PoPKey: popKey,
			},
		),
		public.WithTenantID(msalOptions.TenantID),
	)
	if err != nil {
		return "", -1, fmt.Errorf("failed to create PoP token with username/password flow: %w", err)
	}

	return result.AccessToken, result.ExpiresOn.Unix(), nil
}

// getPublicClient returns an instance of the msal `public` client based on the provided options
// The instance discovery should be disabled on private cloud
func getPublicClient(msalOptions *MsalClientOptions) (*public.Client, error) {
	var client public.Client
	var err error
	if msalOptions == nil {
		return nil, fmt.Errorf("unable to create public client: MsalClientOptions is empty")
	}
	if msalOptions.Options.Transport != nil {
		client, err = public.New(
			msalOptions.ClientID,
			public.WithAuthority(msalOptions.Authority),
			public.WithHTTPClient(msalOptions.Options.Transport.(*http.Client)),
			public.WithInstanceDiscovery(!msalOptions.DisableInstanceDiscovery),
		)
	} else {
		client, err = public.New(
			msalOptions.ClientID,
			public.WithAuthority(msalOptions.Authority),
			public.WithInstanceDiscovery(!msalOptions.DisableInstanceDiscovery),
		)
	}
	if err != nil {
		return nil, fmt.Errorf("unable to create public client: %w", err)
	}

	return &client, nil
}
07070100000063000081A4000000000000000000000001687816E50000163C000000000000000000000000000000000000003600000000kubelogin-0.2.10/pkg/internal/pop/msal_public_test.gopackage pop

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
	"github.com/Azure/kubelogin/pkg/internal/testutils"
	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/public"
	"github.com/golang-jwt/jwt/v4"
)

type resourceOwnerTokenVars struct {
	clientID   string
	username   string
	password   string
	resourceID string
	tenantID   string
	popClaims  map[string]string
}

func TestAcquirePoPTokenByUsernamePassword(t *testing.T) {
	pEnv := &resourceOwnerTokenVars{
		clientID: os.Getenv(testutils.ClientID),
		username: os.Getenv(testutils.Username),
		password: os.Getenv(testutils.Password),
		tenantID: os.Getenv(testutils.TenantID),
	}
	// Use defaults if environmental variables are empty
	if pEnv.clientID == "" {
		pEnv.clientID = testutils.TestClientID
	}
	if pEnv.username == "" {
		pEnv.username = testutils.Username
	}
	if pEnv.password == "" {
		pEnv.password = testutils.Password
	}
	if pEnv.tenantID == "" {
		pEnv.tenantID = testutils.TestTenantID
	}

	ctx := context.Background()
	scopes := []string{testutils.TestServerID + "/.default"}
	authority := "https://login.microsoftonline.com/" + pEnv.tenantID
	var expectedToken string
	expectedTokenType := "pop"
	testCase := []struct {
		cassetteName  string
		p             *resourceOwnerTokenVars
		expectedError error
	}{
		{
			// Test using bad password
			cassetteName: "AcquirePoPTokenByUsernamePasswordFromBadPasswordVCR",
			p: &resourceOwnerTokenVars{
				clientID:   pEnv.clientID,
				username:   pEnv.username,
				password:   testutils.BadSecret,
				resourceID: testutils.TestServerID,
				tenantID:   pEnv.tenantID,
				popClaims:  map[string]string{"u": "testhost"},
			},
			expectedError: fmt.Errorf("failed to create PoP token with username/password flow"),
		},
		{
			// Test using username/password to get PoP token
			cassetteName: "AcquirePoPTokenByUsernamePasswordVCR",
			p: &resourceOwnerTokenVars{
				clientID:   pEnv.clientID,
				username:   pEnv.username,
				password:   pEnv.password,
				resourceID: testutils.TestServerID,
				tenantID:   pEnv.tenantID,
				popClaims:  map[string]string{"u": "testhost"},
			},
			expectedError: nil,
		},
	}

	for _, tc := range testCase {
		t.Run(tc.cassetteName, func(t *testing.T) {
			if tc.expectedError == nil {
				expectedToken = testutils.TestToken
			}
			vcrRecorder, err := testutils.GetVCRHttpClient(fmt.Sprintf("testdata/%s", tc.cassetteName), pEnv.tenantID)
			if err != nil {
				t.Fatalf("failed to create vcr recorder: %s", err)
			}

			token, _, err := AcquirePoPTokenByUsernamePassword(
				ctx,
				tc.p.popClaims,
				scopes,
				tc.p.username,
				tc.p.password,
				&MsalClientOptions{
					Authority: authority,
					ClientID:  tc.p.clientID,
					Options: azcore.ClientOptions{
						Cloud:     cloud.AzurePublic,
						Transport: vcrRecorder.GetDefaultClient(),
					},
					TenantID: tc.p.tenantID,
				},
			)
			defer vcrRecorder.Stop()
			if tc.expectedError != nil {
				if !testutils.ErrorContains(err, tc.expectedError.Error()) {
					t.Errorf("expected error %s, but got %s", tc.expectedError.Error(), err)
				}
			} else if err != nil {
				t.Errorf("expected no error, but got: %s", err)
			} else {
				if token == "" {
					t.Error("expected valid token, but received empty token.")
				}
				claims := jwt.MapClaims{}
				parsed, _ := jwt.ParseWithClaims(token, &claims, nil)
				if claims["at"] != expectedToken {
					t.Errorf("unexpected token returned (expected %s, but got %s)", expectedToken, claims["at"])
				}
				if parsed.Header["typ"] != expectedTokenType {
					t.Errorf("unexpected token returned (expected %s, but got %s)", expectedTokenType, parsed.Header["typ"])
				}
			}
		})
	}
}

func TestGetPublicClient(t *testing.T) {
	httpClient := &http.Client{}
	authority := "https://login.microsoftonline.com/" + testutils.TenantID

	testCase := []struct {
		testName      string
		msalOptions   *MsalClientOptions
		expectedError error
	}{
		{
			// Test using custom HTTP transport
			testName: "TestGetPublicClientWithCustomTransport",
			msalOptions: &MsalClientOptions{
				Authority: authority,
				ClientID:  testutils.ClientID,
				Options: azcore.ClientOptions{
					Cloud:     cloud.AzurePublic,
					Transport: httpClient,
				},
				TenantID: testutils.TenantID,
			},
			expectedError: nil,
		},
		{
			// Test using default HTTP transport
			testName: "TestGetPublicClientWithDefaultTransport",
			msalOptions: &MsalClientOptions{
				Authority: authority,
				ClientID:  testutils.ClientID,
				Options: azcore.ClientOptions{
					Cloud: cloud.AzurePublic,
				},
				TenantID: testutils.TenantID,
			},
			expectedError: nil,
		},
		{
			// Test using incorrectly formatted authority
			testName: "TestGetPublicClientWithBadAuthority",
			msalOptions: &MsalClientOptions{
				Authority: "login.microsoft.com",
				ClientID:  testutils.ClientID,
				Options: azcore.ClientOptions{
					Cloud: cloud.AzurePublic,
				},
				TenantID: testutils.TenantID,
			},
			expectedError: fmt.Errorf("unable to create public client"),
		},
	}

	var client *public.Client
	var err error

	for _, tc := range testCase {
		t.Run(tc.testName, func(t *testing.T) {
			client, err = getPublicClient(tc.msalOptions)

			if tc.expectedError != nil {
				if !testutils.ErrorContains(err, tc.expectedError.Error()) {
					t.Errorf("expected error %s, but got %s", tc.expectedError.Error(), err)
				}
			} else if err != nil {
				t.Errorf("expected no error, but got: %s", err)
			} else {
				if client == nil {
					t.Errorf("expected a client but got nil")
				}
			}
		})
	}
}
07070100000064000081A4000000000000000000000001687816E500001117000000000000000000000000000000000000002E00000000kubelogin-0.2.10/pkg/internal/pop/poptoken.gopackage pop

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"math/big"
)

// PoPKey is a generic interface for PoP key properties and methods
type PoPKey interface {
	// encryption/signature algo
	Alg() string
	// kid
	KeyID() string
	// jwk that can be embedded in JWT w/ PoP token's cnf claim
	JWK() string
	// https://tools.ietf.org/html/rfc7638 compliant jwk thumbprint
	JWKThumbprint() string
	// req_cnf claim that can be included in access token request to AAD
	ReqCnf() string
	// sign payload using private key
	Sign([]byte) ([]byte, error)
}

// software based pop key implementation of PoPKey
type SwKey struct {
	key    *rsa.PrivateKey
	keyID  string
	jwk    string
	jwkTP  string
	reqCnf string
}

// Alg returns the algorithm used to encrypt/sign the SwKey
func (swk *SwKey) Alg() string {
	return "RS256"
}

// KeyID returns the keyID of the SwKey, representing the key used to sign the SwKey
func (swk *SwKey) KeyID() string {
	return swk.keyID
}

// JWK returns the JSON Web Key of the given SwKey
func (swk *SwKey) JWK() string {
	return swk.jwk
}

// JWKThumbprint returns the JWK thumbprint of the given SwKey
func (swk *SwKey) JWKThumbprint() string {
	return swk.jwkTP
}

// ReqCnf returns the req_cnf claim to send to AAD for the given SwKey
func (swk *SwKey) ReqCnf() string {
	return swk.reqCnf
}

// Sign uses the given SwKey to sign the given payload and returns the signed payload
func (swk *SwKey) Sign(payload []byte) ([]byte, error) {
	return swk.key.Sign(rand.Reader, payload, crypto.SHA256)
}

// init initializes the given SwKey using the given private key
func (swk *SwKey) init(key *rsa.PrivateKey) {
	swk.key = key

	eB64, nB64 := getRSAKeyExponentAndModulus(key)
	swk.jwkTP = computeJWKThumbprint(eB64, nB64)
	swk.reqCnf = getReqCnf(swk.jwkTP)

	// set keyID to jwkTP
	swk.keyID = swk.jwkTP

	// compute JWK to be included in JWT w/ PoP token's cnf claim
	// - https://tools.ietf.org/html/rfc7800#section-3.2
	swk.jwk = getJWK(eB64, nB64, swk.keyID)
}

// generateSwKey generates a new SwKey and initializes it with required fields before returning it
func generateSwKey(key *rsa.PrivateKey) (*SwKey, error) {
	swk := &SwKey{}
	swk.init(key)
	return swk, nil
}

// GetSwPoPKey generates a new PoP key returns it
func GetSwPoPKey() (*SwKey, error) {
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, fmt.Errorf("error generating RSA private key: %w", err)
	}
	return GetSwPoPKeyWithRSAKey(key)
}

func GetSwPoPKeyWithRSAKey(rsaKey *rsa.PrivateKey) (*SwKey, error) {
	key, err := generateSwKey(rsaKey)
	if err != nil {
		return nil, fmt.Errorf("unable to generate PoP key. err: %w", err)
	}
	return key, nil
}

// getRSAKeyExponentAndModulus returns the exponent and modulus from the given RSA key
// as base-64 encoded strings
func getRSAKeyExponentAndModulus(rsaKey *rsa.PrivateKey) (string, string) {
	pubKey := rsaKey.PublicKey
	e := big.NewInt(int64(pubKey.E))
	eB64 := base64.RawURLEncoding.EncodeToString(e.Bytes())
	n := pubKey.N
	nB64 := base64.RawURLEncoding.EncodeToString(n.Bytes())
	return eB64, nB64
}

// computeJWKThumbprint returns a computed JWK thumbprint using the given base-64 encoded
// exponent and modulus
func computeJWKThumbprint(eB64 string, nB64 string) string {
	// compute JWK thumbprint
	// jwk format - e, kty, n - in lexicographic order
	// - https://tools.ietf.org/html/rfc7638#section-3.3
	// - https://tools.ietf.org/html/rfc7638#section-3.1
	jwk := fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s"}`, eB64, nB64)
	jwkS256 := sha256.Sum256([]byte(jwk))
	return base64.RawURLEncoding.EncodeToString(jwkS256[:])
}

// getReqCnf computes and returns the value for the req_cnf claim to include when sending
// a request for the token
func getReqCnf(jwkTP string) string {
	// req_cnf - base64URL("{"kid":"jwkTP","xms_ksl":"sw"}")
	reqCnfJSON := fmt.Sprintf(`{"kid":"%s","xms_ksl":"sw"}`, jwkTP)
	return base64.RawURLEncoding.EncodeToString([]byte(reqCnfJSON))
}

// getJWK computes the JWK to be included in the PoP token's enclosed cnf claim and returns it
func getJWK(eB64 string, nB64 string, keyID string) string {
	// compute JWK to be included in JWT w/ PoP token's cnf claim
	// - https://tools.ietf.org/html/rfc7800#section-3.2
	return fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s","alg":"RS256","kid":"%s"}`, eB64, nB64, keyID)
}
07070100000065000081A4000000000000000000000001687816E5000007EC000000000000000000000000000000000000003300000000kubelogin-0.2.10/pkg/internal/pop/poptoken_test.gopackage pop

import (
	"crypto/rand"
	"crypto/rsa"
	"testing"
)

func TestSwPoPKey(t *testing.T) {
	t.Run("GetSwPoPKeyWithRSAKey should return a key with all the expected fields", func(t *testing.T) {
		rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
		if err != nil {
			t.Errorf("expected no error generating RSA key but got: %s", err)
		}
		key, err := GetSwPoPKeyWithRSAKey(rsaKey)
		if err != nil {
			t.Errorf("expected no error but got: %s", err)
		}

		// validate key alg
		if key.Alg() != "RS256" {
			t.Errorf("expected key alg: %s but got: %s", "RS256", key.Alg())
		}

		// validate key jwk thumbprint
		eB64, nB64 := getRSAKeyExponentAndModulus(key.key)
		expectedJWKThumbprint := computeJWKThumbprint(eB64, nB64)
		if key.JWKThumbprint() != expectedJWKThumbprint {
			t.Errorf("expected key jwt thumbprint: %s but got: %s", expectedJWKThumbprint, key.JWKThumbprint())
		}

		// validate req_cnf
		expectedReqCnf := getReqCnf(expectedJWKThumbprint)
		if key.ReqCnf() != expectedReqCnf {
			t.Errorf("expected key req_cnf: %s but got: %s", expectedReqCnf, key.ReqCnf())
		}

		// validate key ID
		if key.KeyID() != expectedJWKThumbprint {
			t.Errorf("expected key ID: %s but got: %s", expectedJWKThumbprint, key.KeyID())
		}

		// validate jwk
		expectedJWK := getJWK(eB64, nB64, expectedJWKThumbprint)
		if key.JWK() != expectedJWK {
			t.Errorf("expected key JWK: %s but got: %s", expectedJWK, key.JWK())
		}
	})

	t.Run("GetSwPoPKeyWithRSAKey should return a key with all the expected fields", func(t *testing.T) {
		rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
		if err != nil {
			t.Errorf("expected no error generating RSA key but got: %s", err)
		}

		e, n := getRSAKeyExponentAndModulus(rsaKey)
		e2, n2 := getRSAKeyExponentAndModulus(rsaKey)
		if e2 != e {
			t.Errorf("%s but got: %s", e, e2)
		}
		if n2 != n {
			t.Errorf("%s but got: %s", n, n2)
		}

		tp1 := computeJWKThumbprint(e, n)
		tp2 := computeJWKThumbprint(e2, n2)
		if tp1 != tp2 {
			t.Errorf("%s but got: %s", tp1, tp2)
		}
	})
}
07070100000066000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002B00000000kubelogin-0.2.10/pkg/internal/pop/testdata07070100000067000081A4000000000000000000000001687816E500006731000000000000000000000000000000000000006400000000kubelogin-0.2.10/pkg/internal/pop/testdata/AcquirePoPTokenByUsernamePasswordFromBadPasswordVCR.yaml---
version: 2
interactions:
    - id: 0
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 23f1fa48-ea1f-4138-be73-75da7aaa0c7b
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 1753
        uncompressed: false
        body: '{"token_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 23f1fa48-ea1f-4138-be73-75da7aaa0c7b
            Content-Length:
                - "1753"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 21 Feb 2024 21:14:22 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.17396.6 - NCUS ProdSlices
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 78.559437ms
    - id: 1
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 3f8be16e-19b1-4199-a330-deb218ca2f7b
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
            client-request-id:
                - 8cab3f9c-f9d3-4a46-bbf6-08ac1eb5d1d6
        url: https://login.microsoftonline.com/common/UserRealm/USERNAME?api-version=1.0
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 384
        uncompressed: false
        body: '{"ver":"1.0","account_type":"Federated","domain_name":"microsoft.com","federation_protocol":"WSTrust","federation_metadata_url":"https://msft.sts.microsoft.com/adfs/services/trust/mex","federation_active_auth_url":"https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed","cloud_instance_name":"microsoftonline.com","cloud_audience_urn":"urn:federation:MicrosoftOnline"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Content-Disposition:
                - inline; filename=userrealm.json
            Content-Length:
                - "384"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 21 Feb 2024 21:14:22 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.17396.6 - WUS3 ProdSlices
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 108.043413ms
    - id: 2
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - df5fd660-b2c5-4f80-832c-8f5e989d84b4
            Content-Type:
                - application/xml; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://msft.sts.microsoft.com/adfs/services/trust/mex
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 14784
        uncompressed: false
        body: <?xml version="1.0" encoding="utf-8"?><wsdl:definitions name="SecurityTokenService" targetNamespace="http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><wsp:Policy wsu:Id="CertificateWSTrustBinding_IWSTrustFeb2005Async_policy"><wsp:ExactlyOne><wsp:All><sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:TransportToken><wsp:Policy><sp:HttpsToken RequireClientCertificate="false"/></wsp:Policy></sp:TransportToken><sp:AlgorithmSuite><wsp:Policy><sp:Basic256/></wsp:Policy></sp:AlgorithmSuite><sp:Layout><wsp:Policy><sp:Strict/></wsp:Policy></sp:Layout><sp:IncludeTimestamp/></wsp:Policy></sp:TransportBinding><sp:EndorsingSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:RequireThumbprintReference/><sp:WssX509V3Token10/></wsp:Policy></sp:X509Token><mssp:RsaToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Never" wsp:Optional="true" xmlns:mssp="http://schemas.microsoft.com/ws/2005/07/securitypolicy"/><sp:SignedParts><sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing"/></sp:SignedParts></wsp:Policy></sp:EndorsingSupportingTokens><sp:Wss11 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:MustSupportRefThumbprint/></wsp:Policy></sp:Wss11><sp:Trust10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:MustSupportIssuedTokens/><sp:RequireClientEntropy/><sp:RequireServerEntropy/></wsp:Policy></sp:Trust10><wsaw:UsingAddressing/></wsp:All></wsp:ExactlyOne></wsp:Policy><wsp:Policy wsu:Id="CertificateWSTrustBinding_IWSTrustFeb2005Async1_policy"><wsp:ExactlyOne><wsp:All><sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:TransportToken><wsp:Policy><sp:HttpsToken RequireClientCertificate="true"/></wsp:Policy></sp:TransportToken><sp:AlgorithmSuite><wsp:Policy><sp:Basic256/></wsp:Policy></sp:AlgorithmSuite><sp:Layout><wsp:Policy><sp:Strict/></wsp:Policy></sp:Layout></wsp:Policy></sp:TransportBinding><wsaw:UsingAddressing/></wsp:All></wsp:ExactlyOne></wsp:Policy><wsp:Policy wsu:Id="UserNameWSTrustBinding_IWSTrustFeb2005Async_policy"><wsp:ExactlyOne><wsp:All><sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:TransportToken><wsp:Policy><sp:HttpsToken RequireClientCertificate="false"/></wsp:Policy></sp:TransportToken><sp:AlgorithmSuite><wsp:Policy><sp:Basic256/></wsp:Policy></sp:AlgorithmSuite><sp:Layout><wsp:Policy><sp:Strict/></wsp:Policy></sp:Layout><sp:IncludeTimestamp/></wsp:Policy></sp:TransportBinding><sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:WssUsernameToken10/></wsp:Policy></sp:UsernameToken></wsp:Policy></sp:SignedSupportingTokens><sp:EndorsingSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><mssp:RsaToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Never" wsp:Optional="true" xmlns:mssp="http://schemas.microsoft.com/ws/2005/07/securitypolicy"/><sp:SignedParts><sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing"/></sp:SignedParts></wsp:Policy></sp:EndorsingSupportingTokens><sp:Wss11 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy/></sp:Wss11><sp:Trust10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:MustSupportIssuedTokens/><sp:RequireClientEntropy/><sp:RequireServerEntropy/></wsp:Policy></sp:Trust10><wsaw:UsingAddressing/></wsp:All></wsp:ExactlyOne></wsp:Policy><wsp:Policy wsu:Id="CertificateWSTrustBinding_IWSTrust13Async_policy"><wsp:ExactlyOne><wsp:All><sp:TransportBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:TransportToken><wsp:Policy><sp:HttpsToken/></wsp:Policy></sp:TransportToken><sp:AlgorithmSuite><wsp:Policy><sp:Basic256/></wsp:Policy></sp:AlgorithmSuite><sp:Layout><wsp:Policy><sp:Strict/></wsp:Policy></sp:Layout><sp:IncludeTimestamp/></wsp:Policy></sp:TransportBinding><sp:EndorsingSupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:RequireThumbprintReference/><sp:WssX509V3Token10/></wsp:Policy></sp:X509Token><sp:KeyValueToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never" wsp:Optional="true"/><sp:SignedParts><sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing"/></sp:SignedParts></wsp:Policy></sp:EndorsingSupportingTokens><sp:Wss11 xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:MustSupportRefThumbprint/></wsp:Policy></sp:Wss11><sp:Trust13 xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:MustSupportIssuedTokens/><sp:RequireClientEntropy/><sp:RequireServerEntropy/></wsp:Policy></sp:Trust13><wsaw:UsingAddressing/></wsp:All></wsp:ExactlyOne></wsp:Policy><wsp:Policy wsu:Id="UserNameWSTrustBinding_IWSTrust13Async_policy"><wsp:ExactlyOne><wsp:All><sp:TransportBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:TransportToken><wsp:Policy><sp:HttpsToken/></wsp:Policy></sp:TransportToken><sp:AlgorithmSuite><wsp:Policy><sp:Basic256/></wsp:Policy></sp:AlgorithmSuite><sp:Layout><wsp:Policy><sp:Strict/></wsp:Policy></sp:Layout><sp:IncludeTimestamp/></wsp:Policy></sp:TransportBinding><sp:SignedEncryptedSupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:WssUsernameToken10/></wsp:Policy></sp:UsernameToken></wsp:Policy></sp:SignedEncryptedSupportingTokens><sp:EndorsingSupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:KeyValueToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never" wsp:Optional="true"/><sp:SignedParts><sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing"/></sp:SignedParts></wsp:Policy></sp:EndorsingSupportingTokens><sp:Wss11 xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy/></sp:Wss11><sp:Trust13 xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:MustSupportIssuedTokens/><sp:RequireClientEntropy/><sp:RequireServerEntropy/></wsp:Policy></sp:Trust13><wsaw:UsingAddressing/></wsp:All></wsp:ExactlyOne></wsp:Policy><wsdl:types><xsd:schema targetNamespace="http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice/Imports"><xsd:import schemaLocation="https://msft.sts.microsoft.com/adfs/services/trust/mex?xsd=xsd0" namespace="http://schemas.microsoft.com/Message"/><xsd:import schemaLocation="https://msft.sts.microsoft.com/adfs/services/trust/mex?xsd=xsd1" namespace="http://schemas.xmlsoap.org/ws/2005/02/trust"/><xsd:import schemaLocation="https://msft.sts.microsoft.com/adfs/services/trust/mex?xsd=xsd2" namespace="http://docs.oasis-open.org/ws-sx/ws-trust/200512"/></xsd:schema></wsdl:types><wsdl:message name="IWSTrustFeb2005Async_TrustFeb2005IssueAsync_InputMessage"><wsdl:part name="request" element="t:RequestSecurityToken"/></wsdl:message><wsdl:message name="IWSTrustFeb2005Async_TrustFeb2005IssueAsync_OutputMessage"><wsdl:part name="TrustFeb2005IssueAsyncResult" element="t:RequestSecurityTokenResponse"/></wsdl:message><wsdl:message name="IWSTrust13Async_Trust13IssueAsync_InputMessage"><wsdl:part name="request" element="trust:RequestSecurityToken"/></wsdl:message><wsdl:message name="IWSTrust13Async_Trust13IssueAsync_OutputMessage"><wsdl:part name="Trust13IssueAsyncResult" element="trust:RequestSecurityTokenResponseCollection"/></wsdl:message><wsdl:portType name="IWSTrustFeb2005Async"><wsdl:operation name="TrustFeb2005IssueAsync"><wsdl:input wsaw:Action="http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue" message="tns:IWSTrustFeb2005Async_TrustFeb2005IssueAsync_InputMessage"/><wsdl:output wsaw:Action="http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue" message="tns:IWSTrustFeb2005Async_TrustFeb2005IssueAsync_OutputMessage"/></wsdl:operation></wsdl:portType><wsdl:portType name="IWSTrust13Async"><wsdl:operation name="Trust13IssueAsync"><wsdl:input wsaw:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" message="tns:IWSTrust13Async_Trust13IssueAsync_InputMessage"/><wsdl:output wsaw:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal" message="tns:IWSTrust13Async_Trust13IssueAsync_OutputMessage"/></wsdl:operation></wsdl:portType><wsdl:binding name="CertificateWSTrustBinding_IWSTrustFeb2005Async" type="tns:IWSTrustFeb2005Async"><wsp:PolicyReference URI="#CertificateWSTrustBinding_IWSTrustFeb2005Async_policy"/><soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="TrustFeb2005IssueAsync"><soap12:operation soapAction="http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue" style="document"/><wsdl:input><soap12:body use="literal"/></wsdl:input><wsdl:output><soap12:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:binding name="CertificateWSTrustBinding_IWSTrustFeb2005Async1" type="tns:IWSTrustFeb2005Async"><wsp:PolicyReference URI="#CertificateWSTrustBinding_IWSTrustFeb2005Async1_policy"/><soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="TrustFeb2005IssueAsync"><soap12:operation soapAction="http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue" style="document"/><wsdl:input><soap12:body use="literal"/></wsdl:input><wsdl:output><soap12:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:binding name="UserNameWSTrustBinding_IWSTrustFeb2005Async" type="tns:IWSTrustFeb2005Async"><wsp:PolicyReference URI="#UserNameWSTrustBinding_IWSTrustFeb2005Async_policy"/><soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="TrustFeb2005IssueAsync"><soap12:operation soapAction="http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue" style="document"/><wsdl:input><soap12:body use="literal"/></wsdl:input><wsdl:output><soap12:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:binding name="CertificateWSTrustBinding_IWSTrust13Async" type="tns:IWSTrust13Async"><wsp:PolicyReference URI="#CertificateWSTrustBinding_IWSTrust13Async_policy"/><soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="Trust13IssueAsync"><soap12:operation soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" style="document"/><wsdl:input><soap12:body use="literal"/></wsdl:input><wsdl:output><soap12:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:binding name="UserNameWSTrustBinding_IWSTrust13Async" type="tns:IWSTrust13Async"><wsp:PolicyReference URI="#UserNameWSTrustBinding_IWSTrust13Async_policy"/><soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="Trust13IssueAsync"><soap12:operation soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" style="document"/><wsdl:input><soap12:body use="literal"/></wsdl:input><wsdl:output><soap12:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:service name="SecurityTokenService"><wsdl:port name="CertificateWSTrustBinding_IWSTrustFeb2005Async" binding="tns:CertificateWSTrustBinding_IWSTrustFeb2005Async"><soap12:address location="https://msft.sts.microsoft.com/adfs/services/trust/2005/certificatemixed"/><wsa10:EndpointReference><wsa10:Address>https://msft.sts.microsoft.com/adfs/services/trust/2005/certificatemixed</wsa10:Address></wsa10:EndpointReference></wsdl:port><wsdl:port name="CertificateWSTrustBinding_IWSTrustFeb2005Async1" binding="tns:CertificateWSTrustBinding_IWSTrustFeb2005Async1"><soap12:address location="https://certauth.msft.sts.microsoft.com/adfs/services/trust/2005/certificatetransport"/><wsa10:EndpointReference><wsa10:Address>https://certauth.msft.sts.microsoft.com/adfs/services/trust/2005/certificatetransport</wsa10:Address></wsa10:EndpointReference></wsdl:port><wsdl:port name="UserNameWSTrustBinding_IWSTrustFeb2005Async" binding="tns:UserNameWSTrustBinding_IWSTrustFeb2005Async"><soap12:address location="https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed"/><wsa10:EndpointReference><wsa10:Address>https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed</wsa10:Address></wsa10:EndpointReference></wsdl:port><wsdl:port name="CertificateWSTrustBinding_IWSTrust13Async" binding="tns:CertificateWSTrustBinding_IWSTrust13Async"><soap12:address location="https://msft.sts.microsoft.com/adfs/services/trust/13/certificatemixed"/><wsa10:EndpointReference><wsa10:Address>https://msft.sts.microsoft.com/adfs/services/trust/13/certificatemixed</wsa10:Address></wsa10:EndpointReference></wsdl:port><wsdl:port name="UserNameWSTrustBinding_IWSTrust13Async" binding="tns:UserNameWSTrustBinding_IWSTrust13Async"><soap12:address location="https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed"/><wsa10:EndpointReference><wsa10:Address>https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed</wsa10:Address></wsa10:EndpointReference></wsdl:port></wsdl:service></wsdl:definitions>
        headers:
            Content-Length:
                - "14784"
            Content-Type:
                - text/xml; charset=UTF-8
            Date:
                - Wed, 21 Feb 2024 21:14:22 GMT
            Server:
                - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0
        status: 200 OK
        code: 200
        duration: 905.127372ms
    - id: 3
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><wsa:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</wsa:Action><wsa:messageID>urn:uuid:1d5fcd63-9609-49ba-a1ed-bd260dfaf6e7</wsa:messageID><wsa:ReplyTo><wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address></wsa:ReplyTo><wsa:To s:mustUnderstand="1">https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed</wsa:To><wsse:Security s:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp wsu:Id="MSATimeStamp"><wsu:Created>2024-02-21T21:14:24.560Z</wsu:Created><wsu:Expires>2024-02-21T21:24:24.560Z</wsu:Expires></wsu:Timestamp><wsse:UsernameToken wsu:Id="UnPwSecTok13-fcb9c6d5-e16c-45b6-b3a9-874ea3213795"><wsse:Username>USERNAME</wsse:Username><wsse:Password>Bad_Secret</wsse:Password></wsse:UsernameToken></wsse:Security></s:Header><s:Body><wst:RequestSecurityToken xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"><wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><wsa:EndpointReference><wsa:Address>urn:federation:MicrosoftOnline</wsa:Address></wsa:EndpointReference></wsp:AppliesTo><wst:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</wst:KeyType><wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</wst:RequestType></wst:RequestSecurityToken></s:Body></s:Envelope>
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 024cc5e1-6771-462d-842b-614f867b7562
            Content-Type:
                - application/soap+xml; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            Soapaction:
                - http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed
        method: POST
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 953
        uncompressed: false
        body: '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><u:Timestamp u:Id="_0"><u:Created>2024-02-21T21:14:25.473Z</u:Created><u:Expires>2024-02-21T21:19:25.473Z</u:Expires></u:Timestamp></o:Security></s:Header><s:Body><s:Fault><s:Code><s:Value>s:Sender</s:Value><s:Subcode><s:Value xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">a:FailedAuthentication</s:Value></s:Subcode></s:Code><s:Reason><s:Text xml:lang="en-US">ID3242: The security token could not be authenticated or authorized.</s:Text></s:Reason></s:Fault></s:Body></s:Envelope>'
        headers:
            Content-Length:
                - "953"
            Content-Type:
                - application/soap+xml; charset=utf-8
            Date:
                - Wed, 21 Feb 2024 21:14:25 GMT
            Server:
                - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0
        status: 500 Internal Server Error
        code: 500
        duration: 1.090492286s
07070100000068000081A4000000000000000000000001687816E50000DF68000000000000000000000000000000000000005500000000kubelogin-0.2.10/pkg/internal/pop/testdata/AcquirePoPTokenByUsernamePasswordVCR.yaml---
version: 2
interactions:
    - id: 0
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 9daec4f1-ed1b-4b64-ba36-d3d34be1a2ac
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 1753
        uncompressed: false
        body: '{"token_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 9daec4f1-ed1b-4b64-ba36-d3d34be1a2ac
            Content-Length:
                - "1753"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 21 Feb 2024 21:14:26 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.17396.6 - WUS3 ProdSlices
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 64.332046ms
    - id: 1
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 42056c1d-e293-4aa2-bb17-97776c6917de
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
            client-request-id:
                - e4609b88-b598-4382-b13a-51bf51f8b458
        url: https://login.microsoftonline.com/common/UserRealm/USERNAME?api-version=1.0
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 384
        uncompressed: false
        body: '{"ver":"1.0","account_type":"Federated","domain_name":"microsoft.com","federation_protocol":"WSTrust","federation_metadata_url":"https://msft.sts.microsoft.com/adfs/services/trust/mex","federation_active_auth_url":"https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed","cloud_instance_name":"microsoftonline.com","cloud_audience_urn":"urn:federation:MicrosoftOnline"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Content-Disposition:
                - inline; filename=userrealm.json
            Content-Length:
                - "384"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 21 Feb 2024 21:14:27 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.17396.6 - WUS3 ProdSlices
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 70.175341ms
    - id: 2
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - fbe23136-87f3-4aa2-98f6-751774fbfa3c
            Content-Type:
                - application/xml; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://msft.sts.microsoft.com/adfs/services/trust/mex
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 14784
        uncompressed: false
        body: <?xml version="1.0" encoding="utf-8"?><wsdl:definitions name="SecurityTokenService" targetNamespace="http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><wsp:Policy wsu:Id="CertificateWSTrustBinding_IWSTrustFeb2005Async_policy"><wsp:ExactlyOne><wsp:All><sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:TransportToken><wsp:Policy><sp:HttpsToken RequireClientCertificate="false"/></wsp:Policy></sp:TransportToken><sp:AlgorithmSuite><wsp:Policy><sp:Basic256/></wsp:Policy></sp:AlgorithmSuite><sp:Layout><wsp:Policy><sp:Strict/></wsp:Policy></sp:Layout><sp:IncludeTimestamp/></wsp:Policy></sp:TransportBinding><sp:EndorsingSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:RequireThumbprintReference/><sp:WssX509V3Token10/></wsp:Policy></sp:X509Token><mssp:RsaToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Never" wsp:Optional="true" xmlns:mssp="http://schemas.microsoft.com/ws/2005/07/securitypolicy"/><sp:SignedParts><sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing"/></sp:SignedParts></wsp:Policy></sp:EndorsingSupportingTokens><sp:Wss11 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:MustSupportRefThumbprint/></wsp:Policy></sp:Wss11><sp:Trust10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:MustSupportIssuedTokens/><sp:RequireClientEntropy/><sp:RequireServerEntropy/></wsp:Policy></sp:Trust10><wsaw:UsingAddressing/></wsp:All></wsp:ExactlyOne></wsp:Policy><wsp:Policy wsu:Id="CertificateWSTrustBinding_IWSTrustFeb2005Async1_policy"><wsp:ExactlyOne><wsp:All><sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:TransportToken><wsp:Policy><sp:HttpsToken RequireClientCertificate="true"/></wsp:Policy></sp:TransportToken><sp:AlgorithmSuite><wsp:Policy><sp:Basic256/></wsp:Policy></sp:AlgorithmSuite><sp:Layout><wsp:Policy><sp:Strict/></wsp:Policy></sp:Layout></wsp:Policy></sp:TransportBinding><wsaw:UsingAddressing/></wsp:All></wsp:ExactlyOne></wsp:Policy><wsp:Policy wsu:Id="UserNameWSTrustBinding_IWSTrustFeb2005Async_policy"><wsp:ExactlyOne><wsp:All><sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:TransportToken><wsp:Policy><sp:HttpsToken RequireClientCertificate="false"/></wsp:Policy></sp:TransportToken><sp:AlgorithmSuite><wsp:Policy><sp:Basic256/></wsp:Policy></sp:AlgorithmSuite><sp:Layout><wsp:Policy><sp:Strict/></wsp:Policy></sp:Layout><sp:IncludeTimestamp/></wsp:Policy></sp:TransportBinding><sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:WssUsernameToken10/></wsp:Policy></sp:UsernameToken></wsp:Policy></sp:SignedSupportingTokens><sp:EndorsingSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><mssp:RsaToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Never" wsp:Optional="true" xmlns:mssp="http://schemas.microsoft.com/ws/2005/07/securitypolicy"/><sp:SignedParts><sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing"/></sp:SignedParts></wsp:Policy></sp:EndorsingSupportingTokens><sp:Wss11 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy/></sp:Wss11><sp:Trust10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"><wsp:Policy><sp:MustSupportIssuedTokens/><sp:RequireClientEntropy/><sp:RequireServerEntropy/></wsp:Policy></sp:Trust10><wsaw:UsingAddressing/></wsp:All></wsp:ExactlyOne></wsp:Policy><wsp:Policy wsu:Id="CertificateWSTrustBinding_IWSTrust13Async_policy"><wsp:ExactlyOne><wsp:All><sp:TransportBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:TransportToken><wsp:Policy><sp:HttpsToken/></wsp:Policy></sp:TransportToken><sp:AlgorithmSuite><wsp:Policy><sp:Basic256/></wsp:Policy></sp:AlgorithmSuite><sp:Layout><wsp:Policy><sp:Strict/></wsp:Policy></sp:Layout><sp:IncludeTimestamp/></wsp:Policy></sp:TransportBinding><sp:EndorsingSupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:RequireThumbprintReference/><sp:WssX509V3Token10/></wsp:Policy></sp:X509Token><sp:KeyValueToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never" wsp:Optional="true"/><sp:SignedParts><sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing"/></sp:SignedParts></wsp:Policy></sp:EndorsingSupportingTokens><sp:Wss11 xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:MustSupportRefThumbprint/></wsp:Policy></sp:Wss11><sp:Trust13 xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:MustSupportIssuedTokens/><sp:RequireClientEntropy/><sp:RequireServerEntropy/></wsp:Policy></sp:Trust13><wsaw:UsingAddressing/></wsp:All></wsp:ExactlyOne></wsp:Policy><wsp:Policy wsu:Id="UserNameWSTrustBinding_IWSTrust13Async_policy"><wsp:ExactlyOne><wsp:All><sp:TransportBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:TransportToken><wsp:Policy><sp:HttpsToken/></wsp:Policy></sp:TransportToken><sp:AlgorithmSuite><wsp:Policy><sp:Basic256/></wsp:Policy></sp:AlgorithmSuite><sp:Layout><wsp:Policy><sp:Strict/></wsp:Policy></sp:Layout><sp:IncludeTimestamp/></wsp:Policy></sp:TransportBinding><sp:SignedEncryptedSupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:WssUsernameToken10/></wsp:Policy></sp:UsernameToken></wsp:Policy></sp:SignedEncryptedSupportingTokens><sp:EndorsingSupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:KeyValueToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never" wsp:Optional="true"/><sp:SignedParts><sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing"/></sp:SignedParts></wsp:Policy></sp:EndorsingSupportingTokens><sp:Wss11 xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy/></sp:Wss11><sp:Trust13 xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"><wsp:Policy><sp:MustSupportIssuedTokens/><sp:RequireClientEntropy/><sp:RequireServerEntropy/></wsp:Policy></sp:Trust13><wsaw:UsingAddressing/></wsp:All></wsp:ExactlyOne></wsp:Policy><wsdl:types><xsd:schema targetNamespace="http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice/Imports"><xsd:import schemaLocation="https://msft.sts.microsoft.com/adfs/services/trust/mex?xsd=xsd0" namespace="http://schemas.microsoft.com/Message"/><xsd:import schemaLocation="https://msft.sts.microsoft.com/adfs/services/trust/mex?xsd=xsd1" namespace="http://schemas.xmlsoap.org/ws/2005/02/trust"/><xsd:import schemaLocation="https://msft.sts.microsoft.com/adfs/services/trust/mex?xsd=xsd2" namespace="http://docs.oasis-open.org/ws-sx/ws-trust/200512"/></xsd:schema></wsdl:types><wsdl:message name="IWSTrustFeb2005Async_TrustFeb2005IssueAsync_InputMessage"><wsdl:part name="request" element="t:RequestSecurityToken"/></wsdl:message><wsdl:message name="IWSTrustFeb2005Async_TrustFeb2005IssueAsync_OutputMessage"><wsdl:part name="TrustFeb2005IssueAsyncResult" element="t:RequestSecurityTokenResponse"/></wsdl:message><wsdl:message name="IWSTrust13Async_Trust13IssueAsync_InputMessage"><wsdl:part name="request" element="trust:RequestSecurityToken"/></wsdl:message><wsdl:message name="IWSTrust13Async_Trust13IssueAsync_OutputMessage"><wsdl:part name="Trust13IssueAsyncResult" element="trust:RequestSecurityTokenResponseCollection"/></wsdl:message><wsdl:portType name="IWSTrustFeb2005Async"><wsdl:operation name="TrustFeb2005IssueAsync"><wsdl:input wsaw:Action="http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue" message="tns:IWSTrustFeb2005Async_TrustFeb2005IssueAsync_InputMessage"/><wsdl:output wsaw:Action="http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue" message="tns:IWSTrustFeb2005Async_TrustFeb2005IssueAsync_OutputMessage"/></wsdl:operation></wsdl:portType><wsdl:portType name="IWSTrust13Async"><wsdl:operation name="Trust13IssueAsync"><wsdl:input wsaw:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" message="tns:IWSTrust13Async_Trust13IssueAsync_InputMessage"/><wsdl:output wsaw:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal" message="tns:IWSTrust13Async_Trust13IssueAsync_OutputMessage"/></wsdl:operation></wsdl:portType><wsdl:binding name="CertificateWSTrustBinding_IWSTrustFeb2005Async" type="tns:IWSTrustFeb2005Async"><wsp:PolicyReference URI="#CertificateWSTrustBinding_IWSTrustFeb2005Async_policy"/><soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="TrustFeb2005IssueAsync"><soap12:operation soapAction="http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue" style="document"/><wsdl:input><soap12:body use="literal"/></wsdl:input><wsdl:output><soap12:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:binding name="CertificateWSTrustBinding_IWSTrustFeb2005Async1" type="tns:IWSTrustFeb2005Async"><wsp:PolicyReference URI="#CertificateWSTrustBinding_IWSTrustFeb2005Async1_policy"/><soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="TrustFeb2005IssueAsync"><soap12:operation soapAction="http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue" style="document"/><wsdl:input><soap12:body use="literal"/></wsdl:input><wsdl:output><soap12:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:binding name="UserNameWSTrustBinding_IWSTrustFeb2005Async" type="tns:IWSTrustFeb2005Async"><wsp:PolicyReference URI="#UserNameWSTrustBinding_IWSTrustFeb2005Async_policy"/><soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="TrustFeb2005IssueAsync"><soap12:operation soapAction="http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue" style="document"/><wsdl:input><soap12:body use="literal"/></wsdl:input><wsdl:output><soap12:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:binding name="CertificateWSTrustBinding_IWSTrust13Async" type="tns:IWSTrust13Async"><wsp:PolicyReference URI="#CertificateWSTrustBinding_IWSTrust13Async_policy"/><soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="Trust13IssueAsync"><soap12:operation soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" style="document"/><wsdl:input><soap12:body use="literal"/></wsdl:input><wsdl:output><soap12:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:binding name="UserNameWSTrustBinding_IWSTrust13Async" type="tns:IWSTrust13Async"><wsp:PolicyReference URI="#UserNameWSTrustBinding_IWSTrust13Async_policy"/><soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="Trust13IssueAsync"><soap12:operation soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" style="document"/><wsdl:input><soap12:body use="literal"/></wsdl:input><wsdl:output><soap12:body use="literal"/></wsdl:output></wsdl:operation></wsdl:binding><wsdl:service name="SecurityTokenService"><wsdl:port name="CertificateWSTrustBinding_IWSTrustFeb2005Async" binding="tns:CertificateWSTrustBinding_IWSTrustFeb2005Async"><soap12:address location="https://msft.sts.microsoft.com/adfs/services/trust/2005/certificatemixed"/><wsa10:EndpointReference><wsa10:Address>https://msft.sts.microsoft.com/adfs/services/trust/2005/certificatemixed</wsa10:Address></wsa10:EndpointReference></wsdl:port><wsdl:port name="CertificateWSTrustBinding_IWSTrustFeb2005Async1" binding="tns:CertificateWSTrustBinding_IWSTrustFeb2005Async1"><soap12:address location="https://certauth.msft.sts.microsoft.com/adfs/services/trust/2005/certificatetransport"/><wsa10:EndpointReference><wsa10:Address>https://certauth.msft.sts.microsoft.com/adfs/services/trust/2005/certificatetransport</wsa10:Address></wsa10:EndpointReference></wsdl:port><wsdl:port name="UserNameWSTrustBinding_IWSTrustFeb2005Async" binding="tns:UserNameWSTrustBinding_IWSTrustFeb2005Async"><soap12:address location="https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed"/><wsa10:EndpointReference><wsa10:Address>https://msft.sts.microsoft.com/adfs/services/trust/2005/usernamemixed</wsa10:Address></wsa10:EndpointReference></wsdl:port><wsdl:port name="CertificateWSTrustBinding_IWSTrust13Async" binding="tns:CertificateWSTrustBinding_IWSTrust13Async"><soap12:address location="https://msft.sts.microsoft.com/adfs/services/trust/13/certificatemixed"/><wsa10:EndpointReference><wsa10:Address>https://msft.sts.microsoft.com/adfs/services/trust/13/certificatemixed</wsa10:Address></wsa10:EndpointReference></wsdl:port><wsdl:port name="UserNameWSTrustBinding_IWSTrust13Async" binding="tns:UserNameWSTrustBinding_IWSTrust13Async"><soap12:address location="https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed"/><wsa10:EndpointReference><wsa10:Address>https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed</wsa10:Address></wsa10:EndpointReference></wsdl:port></wsdl:service></wsdl:definitions>
        headers:
            Content-Length:
                - "14784"
            Content-Type:
                - text/xml; charset=UTF-8
            Date:
                - Wed, 21 Feb 2024 21:14:27 GMT
            Server:
                - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0
        status: 200 OK
        code: 200
        duration: 223.877512ms
    - id: 3
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><wsa:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</wsa:Action><wsa:messageID>urn:uuid:c3163081-59ba-443d-bfe0-4f3c2e343fa7</wsa:messageID><wsa:ReplyTo><wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address></wsa:ReplyTo><wsa:To s:mustUnderstand="1">https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed</wsa:To><wsse:Security s:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp wsu:Id="MSATimeStamp"><wsu:Created>2024-02-21T21:14:27.575Z</wsu:Created><wsu:Expires>2024-02-21T21:24:27.575Z</wsu:Expires></wsu:Timestamp><wsse:UsernameToken wsu:Id="UnPwSecTok13-3e0b3bb9-6e03-4e12-99d6-45a3181c2ec0"><wsse:Username>USERNAME</wsse:Username><wsse:Password>[REDACTED]</wsse:Password></wsse:UsernameToken></wsse:Security></s:Header><s:Body><wst:RequestSecurityToken xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"><wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><wsa:EndpointReference><wsa:Address>urn:federation:MicrosoftOnline</wsa:Address></wsa:EndpointReference></wsp:AppliesTo><wst:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</wst:KeyType><wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</wst:RequestType></wst:RequestSecurityToken></s:Body></s:Envelope>
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - b4273c15-60fd-4be1-b538-10de45a3843b
            Content-Type:
                - application/soap+xml; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            Soapaction:
                - http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://msft.sts.microsoft.com/adfs/services/trust/13/usernamemixed
        method: POST
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 9894
        uncompressed: false
        body: <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal</a:Action><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><u:Timestamp u:Id="_0"><u:Created>2024-02-21T21:14:27.770Z</u:Created><u:Expires>2024-02-21T21:19:27.770Z</u:Expires></u:Timestamp></o:Security></s:Header><s:Body><trust:RequestSecurityTokenResponseCollection xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512"><trust:RequestSecurityTokenResponse><trust:Lifetime><wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2024-02-21T21:14:27.770Z</wsu:Created><wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2024-02-21T22:14:27.770Z</wsu:Expires></trust:Lifetime><wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Address>urn:federation:MicrosoftOnline</wsa:Address></wsa:EndpointReference></wsp:AppliesTo><trust:RequestedSecurityToken><saml:Assertion MajorVersion="1" MinorVersion="1" AssertionID="_cc4cc62c-43fa-4054-95ec-8931c0277f7a" Issuer="urn:federation:MSFT" IssueInstant="2024-02-21T21:14:27.770Z" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"><saml:Conditions NotBefore="2024-02-21T21:14:27.770Z" NotOnOrAfter="2024-02-21T22:14:27.770Z"><saml:AudienceRestrictionCondition><saml:Audience>urn:federation:MicrosoftOnline</saml:Audience></saml:AudienceRestrictionCondition></saml:Conditions><saml:AttributeStatement><saml:Subject><saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">4pGK4tThCkamJqAj33shZA==</saml:NameIdentifier><saml:SubjectConfirmation><saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod></saml:SubjectConfirmation></saml:Subject><saml:Attribute AttributeName="UPN" AttributeNamespace="http://schemas.xmlsoap.org/claims"><saml:AttributeValue>USERNAME</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="objectGUID" AttributeNamespace="http://tempuri.com"><saml:AttributeValue>4pGK4tThCkamJqAj33shZA==</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="PersonnelNumber" AttributeNamespace="http://schemas.xmlsoap.org/claims"><saml:AttributeValue>4pGK4tThCkamJqAj33shZA==</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="ImmutableID" AttributeNamespace="http://schemas.microsoft.com/LiveID/Federation/2008/05"><saml:AttributeValue>4pGK4tThCkamJqAj33shZA==</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="authnmethodsreferences" AttributeNamespace="http://schemas.microsoft.com/claims"><saml:AttributeValue>http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/password</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="passwordexpirationtime" AttributeNamespace="http://schemas.microsoft.com/ws/2012/01"><saml:AttributeValue>2024-09-21T21:00:03.757Z</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="passwordchangeurl" AttributeNamespace="http://schemas.microsoft.com/ws/2012/01"><saml:AttributeValue>https://sspm.microsoft.com</saml:AttributeValue></saml:Attribute><saml:Attribute AttributeName="client-request-id" AttributeNamespace="http://schemas.microsoft.com/2012/01/requestcontext/claims" a:OriginalIssuer="CLIENT CONTEXT" xmlns:a="http://schemas.xmlsoap.org/ws/2009/09/identity/claims"><saml:AttributeValue>b4273c15-60fd-4be1-b538-10de45a3843b</saml:AttributeValue></saml:Attribute></saml:AttributeStatement><saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" AuthenticationInstant="2024-02-21T21:14:27.707Z"><saml:Subject><saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">4pGK4tThCkamJqAj33shZA==</saml:NameIdentifier><saml:SubjectConfirmation><saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod></saml:SubjectConfirmation></saml:Subject></saml:AuthenticationStatement><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#_cc4cc62c-43fa-4054-95ec-8931c0277f7a"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>4z/sZaVjT/ZhsGdXQwVeYihESqV+FXtqXkacypO15hY=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>tkdyR3za2kbPQAHW/6SEquQ3Lgn+331U9mZnrRFKP1MnwTvfD9GpEw+5dVxQtwqAIqD9p1WwDqbiID7agTWaE8d8bmBk21KXbxhMP7+3Gju2MHLbF9AHI9LfBQVClGcerv2EbrnlE/mF3cPEcbWVp5x2EtD00qxd+1Tw1yzEO7LFSxN+cpFf/SQvqn6Zyyn3RzpEIycCV9EgXWLeKul47rbaaEkWYR1RNx8o68OqNROCAqMH1GG7n4bcoCzj+/pNwRBVhl7FzFQFyWCyN8br01gQge61fLT71nRSCbiuTa7O8j7LjdLGGlfH9GEclBHwEQEUFD6AKVDaJBEhPm+ezw==</ds:SignatureValue><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><X509Data><X509Certificate>MIIIcDCCBligAwIBAgITMwAhKgLCjrUMx2lihwAAACEqAjANBgkqhkiG9w0BAQwFADBdMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS4wLAYDVQQDEyVNaWNyb3NvZnQgQXp1cmUgUlNBIFRMUyBJc3N1aW5nIENBIDA0MB4XDTI0MDExNjE4MTQyNVoXDTI1MDExMDE4MTQyNVowbTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xHzAdBgNVBAMTFm1zZnQuc3RzLm1pY3Jvc29mdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFKlsVGXV9JFOdUJOp49zbcI1UtywMFp4Vr7DVDYjzlEk8gF8wUJFhqOc56oZU0jKBoAWkC0sefpfXmdazb7YsCFjpUZ/pWel0iNsmDHiAl+ytfyhyi+BnkCJCrCTJiaK2VNp0QgYHJl6KppVYFWuAr3UVhyGtCxcoZruYLBlb7UN2T6AbR3a6WKhD58RRADa4EbecCon6MtVv9AeQdi+izK7hhIGeg5CPMuIEO02d+KgArLlXADm3JO5ie/JtnoPSMsCAhJQGqKxja28IlJ4VorMjTuV5l70x7VUVBg2EIgp+vgJ8F51KXPbQKuJvyXSCLEl+ff7tPjFhi2i3gE/JAgMBAAGjggQXMIIEEzCCAX0GCisGAQQB1nkCBAIEggFtBIIBaQFnAHUATnWjJ1yaEMM4W2zU3z9S6x3w4I4bjWnAsfpksWKaOd8AAAGNE4SG1gAABAMARjBEAiAqXG3UtSbli3eYUIlNk8SIQYU5JdxQkczonOkap+c3OgIgMY2pZGBgr7WdAQA50DBTh8U7OiQ3dPvm1J+TJtVhxUoAdgB9WR4S4XgqexxhZ3xe/fjQh1wUoE6VnrkDL9kOjC55uAAAAY0ThIasAAAEAwBHMEUCIEriWEtcKIzCmm83LZK9m7qH7UpqUy8QMKwZtO/62i6sAiEAg70AUsGhNParA/5gPOkNpMaWvIlb7Lj49XIwDPWr7VEAdgBVgdTCFpA2AUrqC5tXPFPwwOQ4eHAlCBcvo6odBxPTDAAAAY0ThIinAAAEAwBHMEUCIQDXImoDIidH9pqtZVrkPXbz2pajKmhVtlJF9zOD8f7HXgIgaYX9XcmnPSqmj6Ad0j+nB1f1KGaou3wb+AHIfA4ezAEwJwYJKwYBBAGCNxUKBBowGDAKBggrBgEFBQcDAjAKBggrBgEFBQcDATA8BgkrBgEEAYI3FQcELzAtBiUrBgEEAYI3FQiHvdcbgefrRoKBnS6O0AyH8NodXYKE5WmC86c+AgFkAgEmMIG0BggrBgEFBQcBAQSBpzCBpDBzBggrBgEFBQcwAoZnaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBBenVyZSUyMFJTQSUyMFRMUyUyMElzc3VpbmclMjBDQSUyMDA0JTIwLSUyMHhzaWduLmNydDAtBggrBgEFBQcwAYYhaHR0cDovL29uZW9jc3AubWljcm9zb2Z0LmNvbS9vY3NwMB0GA1UdDgQWBBQWstn/NHMw8B02sgLNcALZxKMNMTAOBgNVHQ8BAf8EBAMCBaAwIQYDVR0RBBowGIIWbXNmdC5zdHMubWljcm9zb2Z0LmNvbTAMBgNVHRMBAf8EAjAAMGoGA1UdHwRjMGEwX6BdoFuGWWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMEF6dXJlJTIwUlNBJTIwVExTJTIwSXNzdWluZyUyMENBJTIwMDQuY3JsMGYGA1UdIARfMF0wUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAIBgZngQwBAgIwHwYDVR0jBBgwFoAUO3DRU+l2JZ1gqMpmD8abrm9UFmowHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBDAUAA4ICAQAE29MX1vYdWSlJWt8Pirt8WTgIjuKJAf1orLOo3SP27mlrb6PrAfmTLX7US8nmiW6mZF29xW8govfZBMs6w0Xxwj7Z9wFP6h8XCS/38vRHPfES0PgVHiQ4X5N5gDvk9QASWStnW8jUhZ/1fCIwsF6tT7Rrd3S79aUF8FEWV/s5SKE3gu7PkW91BT44nFq1zz3cil5B768D4M0Ip9dcuZ+tejkbPkWVwFhv6vlwWySyruIIZ5MeDzhaJDhVjHD7WiF3+6iUhEIwONE3JhUSRL1tR6ifbFxhJwTxoQm6LL7mCcqdFGFfshRQx9717tPpR0lGVgqnYxlBwv2lSgzhl+mWjy4C8tzgKthgNBhY5n7Rml5FAjfA6cUPQh60ws30AdSaKDZ8kVM1qLKUoAd5hjB/ZwHFNFoYQgr1bgTcsylw4A+3wuJO6f/r4fZuoh3TJjil290XFgvp76oLeMxX7zonW3HSb/cNTeFLNeF3sUbuQS0hxMzwnj6jjIzFJxas54JZrpkrv2XptzDvbeeg3oNARGtG4NF4NAfaTV/c4ArGxtgQl4WxebU5Uz9Rv9WkflJ4nAi/Dkx/9dbnQi7VkT7fBt0bvr9Hab6GfZ62GtlEg6eiZ5b8ZiNHPb35HWKXKDNnpWoicX+lmWjfGAYtdcS64DX3gmW3xso/7We6EKR3bw==</X509Certificate></X509Data></KeyInfo></ds:Signature></saml:Assertion></trust:RequestedSecurityToken><trust:RequestedAttachedReference><o:SecurityTokenReference k:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:k="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"><o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">_cc4cc62c-43fa-4054-95ec-8931c0277f7a</o:KeyIdentifier></o:SecurityTokenReference></trust:RequestedAttachedReference><trust:RequestedUnattachedReference><o:SecurityTokenReference k:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:k="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"><o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">_cc4cc62c-43fa-4054-95ec-8931c0277f7a</o:KeyIdentifier></o:SecurityTokenReference></trust:RequestedUnattachedReference><trust:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</trust:TokenType><trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType><trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType></trust:RequestSecurityTokenResponse></trust:RequestSecurityTokenResponseCollection></s:Body></s:Envelope>
        headers:
            Content-Length:
                - "9894"
            Content-Type:
                - application/soap+xml; charset=utf-8
            Date:
                - Wed, 21 Feb 2024 21:14:27 GMT
            Server:
                - Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0
        status: 200 OK
        code: 200
        duration: 382.05008ms
    - id: 4
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 9902
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: assertion=PHNhbWw6QXNzZXJ0aW9uIE1ham9yVmVyc2lvbj0iMSIgTWlub3JWZXJzaW9uPSIxIiBBc3NlcnRpb25JRD0iX2NjNGNjNjJjLTQzZmEtNDA1NC05NWVjLTg5MzFjMDI3N2Y3YSIgSXNzdWVyPSJ1cm46ZmVkZXJhdGlvbjpNU0ZUIiBJc3N1ZUluc3RhbnQ9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzcwWiIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFzc2VydGlvbiI%2BPHNhbWw6Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzcwWiIgTm90T25PckFmdGVyPSIyMDI0LTAyLTIxVDIyOjE0OjI3Ljc3MFoiPjxzYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb25Db25kaXRpb24%2BPHNhbWw6QXVkaWVuY2U%2BdXJuOmZlZGVyYXRpb246TWljcm9zb2Z0T25saW5lPC9zYW1sOkF1ZGllbmNlPjwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uQ29uZGl0aW9uPjwvc2FtbDpDb25kaXRpb25zPjxzYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJZGVudGlmaWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6dW5zcGVjaWZpZWQiPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpOYW1lSWRlbnRpZmllcj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjxzYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6Y206YmVhcmVyPC9zYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0iVVBOIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL2NsYWltcyI%2BPHNhbWw6QXR0cmlidXRlVmFsdWU%2Bazhjb25uZWN0c2FAbWljcm9zb2Z0LmNvbTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJvYmplY3RHVUlEIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly90ZW1wdXJpLmNvbSI%2BPHNhbWw6QXR0cmlidXRlVmFsdWU%2BNHBHSzR0VGhDa2FtSnFBajMzc2haQT09PC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU%2BPHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9IlBlcnNvbm5lbE51bWJlciIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy9jbGFpbXMiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJJbW11dGFibGVJRCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL0xpdmVJRC9GZWRlcmF0aW9uLzIwMDgvMDUiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJhdXRobm1ldGhvZHNyZWZlcmVuY2VzIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vY2xhaW1zIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZT5odHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvYXV0aGVudGljYXRpb25tZXRob2QvcGFzc3dvcmQ8L3NhbWw6QXR0cmlidXRlVmFsdWU%2BPC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0icGFzc3dvcmRleHBpcmF0aW9udGltZSIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjIwMjQtMDktMjFUMjE6MDA6MDMuNzU3Wjwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJwYXNzd29yZGNoYW5nZXVybCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPmh0dHBzOi8vc3NwbS5taWNyb3NvZnQuY29tPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU%2BPHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9ImNsaWVudC1yZXF1ZXN0LWlkIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vMjAxMi8wMS9yZXF1ZXN0Y29udGV4dC9jbGFpbXMiIGE6T3JpZ2luYWxJc3N1ZXI9IkNMSUVOVCBDT05URVhUIiB4bWxuczphPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA5LzA5L2lkZW50aXR5L2NsYWltcyI%2BPHNhbWw6QXR0cmlidXRlVmFsdWU%2BYjQyNzNjMTUtNjBmZC00YmUxLWI1MzgtMTBkZTQ1YTM4NDNiPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU%2BPC9zYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpBdXRoZW50aWNhdGlvblN0YXRlbWVudCBBdXRoZW50aWNhdGlvbk1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFtOnBhc3N3b3JkIiBBdXRoZW50aWNhdGlvbkluc3RhbnQ9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzA3WiI%2BPHNhbWw6U3ViamVjdD48c2FtbDpOYW1lSWRlbnRpZmllciBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OnVuc3BlY2lmaWVkIj40cEdLNHRUaENrYW1KcUFqMzNzaFpBPT08L3NhbWw6TmFtZUlkZW50aWZpZXI%2BPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48c2FtbDpDb25maXJtYXRpb25NZXRob2Q%2BdXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmNtOmJlYXJlcjwvc2FtbDpDb25maXJtYXRpb25NZXRob2Q%2BPC9zYW1sOlN1YmplY3RDb25maXJtYXRpb24%2BPC9zYW1sOlN1YmplY3Q%2BPC9zYW1sOkF1dGhlbnRpY2F0aW9uU3RhdGVtZW50PjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8%2BPGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI19jYzRjYzYyYy00M2ZhLTQwNTQtOTVlYy04OTMxYzAyNzdmN2EiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM%2BPGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT40ei9zWmFWalQvWmhzR2RYUXdWZVlpaEVTcVYrRlh0cVhrYWN5cE8xNWhZPTwvZHM6RGlnZXN0VmFsdWU%2BPC9kczpSZWZlcmVuY2U%2BPC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT50a2R5UjN6YTJrYlBRQUhXLzZTRXF1UTNMZ24rMzMxVTltWm5yUkZLUDFNbndUdmZEOUdwRXcrNWRWeFF0d3FBSXFEOXAxV3dEcWJpSUQ3YWdUV2FFOGQ4Ym1CazIxS1hieGhNUDcrM0dqdTJNSExiRjlBSEk5TGZCUVZDbEdjZXJ2MkVicm5sRS9tRjNjUEVjYldWcDV4MkV0RDAwcXhkKzFUdzF5ekVPN0xGU3hOK2NwRmYvU1F2cW42Wnl5bjNSenBFSXljQ1Y5RWdYV0xlS3VsNDdyYmFhRWtXWVIxUk54OG82OE9xTlJPQ0FxTUgxR0c3bjRiY29DemorL3BOd1JCVmhsN0Z6RlFGeVdDeU44YnIwMWdRZ2U2MWZMVDcxblJTQ2JpdVRhN084ajdMamRMR0dsZkg5R0VjbEJId0VRRVVGRDZBS1ZEYUpCRWhQbStlenc9PTwvZHM6U2lnbmF0dXJlVmFsdWU%2BPEtleUluZm8geG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxYNTA5RGF0YT48WDUwOUNlcnRpZmljYXRlPk1JSUljRENDQmxpZ0F3SUJBZ0lUTXdBaEtnTENqclVNeDJsaWh3QUFBQ0VxQWpBTkJna3Foa2lHOXcwQkFRd0ZBREJkTVFzd0NRWURWUVFHRXdKVlV6RWVNQndHQTFVRUNoTVZUV2xqY205emIyWjBJRU52Y25CdmNtRjBhVzl1TVM0d0xBWURWUVFERXlWTmFXTnliM052Wm5RZ1FYcDFjbVVnVWxOQklGUk1VeUJKYzNOMWFXNW5JRU5CSURBME1CNFhEVEkwTURFeE5qRTRNVFF5TlZvWERUSTFNREV4TURFNE1UUXlOVm93YlRFTE1Ba0dBMVVFQmhNQ1ZWTXhDekFKQmdOVkJBZ1RBbGRCTVJBd0RnWURWUVFIRXdkU1pXUnRiMjVrTVI0d0hBWURWUVFLRXhWTmFXTnliM052Wm5RZ1EyOXljRzl5WVhScGIyNHhIekFkQmdOVkJBTVRGbTF6Wm5RdWMzUnpMbTFwWTNKdmMyOW1kQzVqYjIwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURGS2xzVkdYVjlKRk9kVUpPcDQ5emJjSTFVdHl3TUZwNFZyN0RWRFlqemxFazhnRjh3VUpGaHFPYzU2b1pVMGpLQm9BV2tDMHNlZnBmWG1kYXpiN1lzQ0ZqcFVaL3BXZWwwaU5zbURIaUFsK3l0ZnloeWkrQm5rQ0pDckNUSmlhSzJWTnAwUWdZSEpsNktwcFZZRld1QXIzVVZoeUd0Q3hjb1pydVlMQmxiN1VOMlQ2QWJSM2E2V0toRDU4UlJBRGE0RWJlY0NvbjZNdFZ2OUFlUWRpK2l6SzdoaElHZWc1Q1BNdUlFTzAyZCtLZ0FyTGxYQURtM0pPNWllL0p0bm9QU01zQ0FoSlFHcUt4amEyOElsSjRWb3JNalR1VjVsNzB4N1ZVVkJnMkVJZ3ArdmdKOEY1MUtYUGJRS3VKdnlYU0NMRWwrZmY3dFBqRmhpMmkzZ0UvSkFnTUJBQUdqZ2dRWE1JSUVFekNDQVgwR0Npc0dBUVFCMW5rQ0JBSUVnZ0Z0QklJQmFRRm5BSFVBVG5XakoxeWFFTU00VzJ6VTN6OVM2eDN3NEk0YmpXbkFzZnBrc1dLYU9kOEFBQUdORTRTRzFnQUFCQU1BUmpCRUFpQXFYRzNVdFNibGkzZVlVSWxOazhTSVFZVTVKZHhRa2N6b25Pa2FwK2MzT2dJZ01ZMnBaR0JncjdXZEFRQTUwREJUaDhVN09pUTNkUHZtMUorVEp0Vmh4VW9BZGdCOVdSNFM0WGdxZXh4aFozeGUvZmpRaDF3VW9FNlZucmtETDlrT2pDNTV1QUFBQVkwVGhJYXNBQUFFQXdCSE1FVUNJRXJpV0V0Y0tJekNtbTgzTFpLOW03cUg3VXBxVXk4UU1Ld1p0Ty82Mmk2c0FpRUFnNzBBVXNHaE5QYXJBLzVnUE9rTnBNYVd2SWxiN0xqNDlYSXdEUFdyN1ZFQWRnQlZnZFRDRnBBMkFVcnFDNXRYUEZQd3dPUTRlSEFsQ0Jjdm82b2RCeFBUREFBQUFZMFRoSWluQUFBRUF3QkhNRVVDSVFEWEltb0RJaWRIOXBxdFpWcmtQWGJ6MnBhakttaFZ0bEpGOXpPRDhmN0hYZ0lnYVlYOVhjbW5QU3FtajZBZDBqK25CMWYxS0dhb3Uzd2IrQUhJZkE0ZXpBRXdKd1lKS3dZQkJBR0NOeFVLQkJvd0dEQUtCZ2dyQmdFRkJRY0RBakFLQmdnckJnRUZCUWNEQVRBOEJna3JCZ0VFQVlJM0ZRY0VMekF0QmlVckJnRUVBWUkzRlFpSHZkY2JnZWZyUm9LQm5TNk8wQXlIOE5vZFhZS0U1V21DODZjK0FnRmtBZ0VtTUlHMEJnZ3JCZ0VGQlFjQkFRU0JwekNCcERCekJnZ3JCZ0VGQlFjd0FvWm5hSFIwY0RvdkwzZDNkeTV0YVdOeWIzTnZablF1WTI5dEwzQnJhVzl3Y3k5alpYSjBjeTlOYVdOeWIzTnZablFsTWpCQmVuVnlaU1V5TUZKVFFTVXlNRlJNVXlVeU1FbHpjM1ZwYm1jbE1qQkRRU1V5TURBMEpUSXdMU1V5TUhoemFXZHVMbU55ZERBdEJnZ3JCZ0VGQlFjd0FZWWhhSFIwY0RvdkwyOXVaVzlqYzNBdWJXbGpjbTl6YjJaMExtTnZiUzl2WTNOd01CMEdBMVVkRGdRV0JCUVdzdG4vTkhNdzhCMDJzZ0xOY0FMWnhLTU5NVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdJUVlEVlIwUkJCb3dHSUlXYlhObWRDNXpkSE11YldsamNtOXpiMlowTG1OdmJUQU1CZ05WSFJNQkFmOEVBakFBTUdvR0ExVWRId1JqTUdFd1g2QmRvRnVHV1doMGRIQTZMeTkzZDNjdWJXbGpjbTl6YjJaMExtTnZiUzl3YTJsdmNITXZZM0pzTDAxcFkzSnZjMjltZENVeU1FRjZkWEpsSlRJd1VsTkJKVEl3VkV4VEpUSXdTWE56ZFdsdVp5VXlNRU5CSlRJd01EUXVZM0pzTUdZR0ExVWRJQVJmTUYwd1VRWU1Ld1lCQkFHQ04weURmUUVCTUVFd1B3WUlLd1lCQlFVSEFnRVdNMmgwZEhBNkx5OTNkM2N1YldsamNtOXpiMlowTG1OdmJTOXdhMmx2Y0hNdlJHOWpjeTlTWlhCdmMybDBiM0o1TG1oMGJUQUlCZ1puZ1F3QkFnSXdId1lEVlIwakJCZ3dGb0FVTzNEUlUrbDJKWjFncU1wbUQ4YWJybTlVRm1vd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3SUdDQ3NHQVFVRkJ3TUJNQTBHQ1NxR1NJYjNEUUVCREFVQUE0SUNBUUFFMjlNWDF2WWRXU2xKV3Q4UGlydDhXVGdJanVLSkFmMW9yTE9vM1NQMjdtbHJiNlByQWZtVExYN1VTOG5taVc2bVpGMjl4Vzhnb3ZmWkJNczZ3MFh4d2o3Wjl3RlA2aDhYQ1MvMzh2UkhQZkVTMFBnVkhpUTRYNU41Z0R2azlRQVNXU3RuVzhqVWhaLzFmQ0l3c0Y2dFQ3UnJkM1M3OWFVRjhGRVdWL3M1U0tFM2d1N1BrVzkxQlQ0NG5GcTF6ejNjaWw1Qjc2OEQ0TTBJcDlkY3VaK3RlamtiUGtXVndGaHY2dmx3V3lTeXJ1SUlaNU1lRHpoYUpEaFZqSEQ3V2lGMys2aVVoRUl3T05FM0poVVNSTDF0UjZpZmJGeGhKd1R4b1FtNkxMN21DY3FkRkdGZnNoUlF4OTcxN3RQcFIwbEdWZ3FuWXhsQnd2MmxTZ3pobCttV2p5NEM4dHpnS3RoZ05CaFk1bjdSbWw1RkFqZkE2Y1VQUWg2MHdzMzBBZFNhS0RaOGtWTTFxTEtVb0FkNWhqQi9ad0hGTkZvWVFncjFiZ1Rjc3lsdzRBKzN3dUpPNmYvcjRmWnVvaDNUSmppbDI5MFhGZ3ZwNzZvTGVNeFg3em9uVzNIU2IvY05UZUZMTmVGM3NVYnVRUzBoeE16d25qNmpqSXpGSnhhczU0SlpycGtydjJYcHR6RHZiZWVnM29OQVJHdEc0TkY0TkFmYVRWL2M0QXJHeHRnUWw0V3hlYlU1VXo5UnY5V2tmbEo0bkFpL0RreC85ZGJuUWk3VmtUN2ZCdDBidnI5SGFiNkdmWjYyR3RsRWc2ZWlaNWI4WmlOSFBiMzVIV0tYS0RObnBXb2ljWCtsbVdqZkdBWXRkY1M2NERYM2dtVzN4c28vN1dlNkVLUjNidz09PC9YNTA5Q2VydGlmaWNhdGU%2BPC9YNTA5RGF0YT48L0tleUluZm8%2BPC9kczpTaWduYXR1cmU%2BPC9zYW1sOkFzc2VydGlvbj4%3D&client_id=[REDACTED]&client_info=1&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml1_1-bearer&password=[REDACTED]&req_cnf=[REDACTED]&scope=6256c85f-0aad-4d50-b960-e6e9b21efe35%2F.default+openid+offline_access+profile&token_type=pop&username=USERNAME
        form:
            assertion:
                - PHNhbWw6QXNzZXJ0aW9uIE1ham9yVmVyc2lvbj0iMSIgTWlub3JWZXJzaW9uPSIxIiBBc3NlcnRpb25JRD0iX2NjNGNjNjJjLTQzZmEtNDA1NC05NWVjLTg5MzFjMDI3N2Y3YSIgSXNzdWVyPSJ1cm46ZmVkZXJhdGlvbjpNU0ZUIiBJc3N1ZUluc3RhbnQ9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzcwWiIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFzc2VydGlvbiI+PHNhbWw6Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzcwWiIgTm90T25PckFmdGVyPSIyMDI0LTAyLTIxVDIyOjE0OjI3Ljc3MFoiPjxzYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb25Db25kaXRpb24+PHNhbWw6QXVkaWVuY2U+dXJuOmZlZGVyYXRpb246TWljcm9zb2Z0T25saW5lPC9zYW1sOkF1ZGllbmNlPjwvc2FtbDpBdWRpZW5jZVJlc3RyaWN0aW9uQ29uZGl0aW9uPjwvc2FtbDpDb25kaXRpb25zPjxzYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJZGVudGlmaWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6dW5zcGVjaWZpZWQiPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpOYW1lSWRlbnRpZmllcj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjxzYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6Y206YmVhcmVyPC9zYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0iVVBOIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL2NsYWltcyI+PHNhbWw6QXR0cmlidXRlVmFsdWU+azhjb25uZWN0c2FAbWljcm9zb2Z0LmNvbTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJvYmplY3RHVUlEIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly90ZW1wdXJpLmNvbSI+PHNhbWw6QXR0cmlidXRlVmFsdWU+NHBHSzR0VGhDa2FtSnFBajMzc2haQT09PC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9IlBlcnNvbm5lbE51bWJlciIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy9jbGFpbXMiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJJbW11dGFibGVJRCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL0xpdmVJRC9GZWRlcmF0aW9uLzIwMDgvMDUiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjRwR0s0dFRoQ2thbUpxQWozM3NoWkE9PTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJhdXRobm1ldGhvZHNyZWZlcmVuY2VzIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vY2xhaW1zIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZT5odHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvYXV0aGVudGljYXRpb25tZXRob2QvcGFzc3dvcmQ8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0icGFzc3dvcmRleHBpcmF0aW9udGltZSIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPjIwMjQtMDktMjFUMjE6MDA6MDMuNzU3Wjwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBBdHRyaWJ1dGVOYW1lPSJwYXNzd29yZGNoYW5nZXVybCIgQXR0cmlidXRlTmFtZXNwYWNlPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMTIvMDEiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlPmh0dHBzOi8vc3NwbS5taWNyb3NvZnQuY29tPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIEF0dHJpYnV0ZU5hbWU9ImNsaWVudC1yZXF1ZXN0LWlkIiBBdHRyaWJ1dGVOYW1lc3BhY2U9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vMjAxMi8wMS9yZXF1ZXN0Y29udGV4dC9jbGFpbXMiIGE6T3JpZ2luYWxJc3N1ZXI9IkNMSUVOVCBDT05URVhUIiB4bWxuczphPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA5LzA5L2lkZW50aXR5L2NsYWltcyI+PHNhbWw6QXR0cmlidXRlVmFsdWU+YjQyNzNjMTUtNjBmZC00YmUxLWI1MzgtMTBkZTQ1YTM4NDNiPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PC9zYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDpBdXRoZW50aWNhdGlvblN0YXRlbWVudCBBdXRoZW50aWNhdGlvbk1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmFtOnBhc3N3b3JkIiBBdXRoZW50aWNhdGlvbkluc3RhbnQ9IjIwMjQtMDItMjFUMjE6MTQ6MjcuNzA3WiI+PHNhbWw6U3ViamVjdD48c2FtbDpOYW1lSWRlbnRpZmllciBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OnVuc3BlY2lmaWVkIj40cEdLNHRUaENrYW1KcUFqMzNzaFpBPT08L3NhbWw6TmFtZUlkZW50aWZpZXI+PHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48c2FtbDpDb25maXJtYXRpb25NZXRob2Q+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4wOmNtOmJlYXJlcjwvc2FtbDpDb25maXJtYXRpb25NZXRob2Q+PC9zYW1sOlN1YmplY3RDb25maXJtYXRpb24+PC9zYW1sOlN1YmplY3Q+PC9zYW1sOkF1dGhlbnRpY2F0aW9uU3RhdGVtZW50PjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI19jYzRjYzYyYy00M2ZhLTQwNTQtOTVlYy04OTMxYzAyNzdmN2EiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT40ei9zWmFWalQvWmhzR2RYUXdWZVlpaEVTcVYrRlh0cVhrYWN5cE8xNWhZPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT50a2R5UjN6YTJrYlBRQUhXLzZTRXF1UTNMZ24rMzMxVTltWm5yUkZLUDFNbndUdmZEOUdwRXcrNWRWeFF0d3FBSXFEOXAxV3dEcWJpSUQ3YWdUV2FFOGQ4Ym1CazIxS1hieGhNUDcrM0dqdTJNSExiRjlBSEk5TGZCUVZDbEdjZXJ2MkVicm5sRS9tRjNjUEVjYldWcDV4MkV0RDAwcXhkKzFUdzF5ekVPN0xGU3hOK2NwRmYvU1F2cW42Wnl5bjNSenBFSXljQ1Y5RWdYV0xlS3VsNDdyYmFhRWtXWVIxUk54OG82OE9xTlJPQ0FxTUgxR0c3bjRiY29DemorL3BOd1JCVmhsN0Z6RlFGeVdDeU44YnIwMWdRZ2U2MWZMVDcxblJTQ2JpdVRhN084ajdMamRMR0dsZkg5R0VjbEJId0VRRVVGRDZBS1ZEYUpCRWhQbStlenc9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PEtleUluZm8geG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxYNTA5RGF0YT48WDUwOUNlcnRpZmljYXRlPk1JSUljRENDQmxpZ0F3SUJBZ0lUTXdBaEtnTENqclVNeDJsaWh3QUFBQ0VxQWpBTkJna3Foa2lHOXcwQkFRd0ZBREJkTVFzd0NRWURWUVFHRXdKVlV6RWVNQndHQTFVRUNoTVZUV2xqY205emIyWjBJRU52Y25CdmNtRjBhVzl1TVM0d0xBWURWUVFERXlWTmFXTnliM052Wm5RZ1FYcDFjbVVnVWxOQklGUk1VeUJKYzNOMWFXNW5JRU5CSURBME1CNFhEVEkwTURFeE5qRTRNVFF5TlZvWERUSTFNREV4TURFNE1UUXlOVm93YlRFTE1Ba0dBMVVFQmhNQ1ZWTXhDekFKQmdOVkJBZ1RBbGRCTVJBd0RnWURWUVFIRXdkU1pXUnRiMjVrTVI0d0hBWURWUVFLRXhWTmFXTnliM052Wm5RZ1EyOXljRzl5WVhScGIyNHhIekFkQmdOVkJBTVRGbTF6Wm5RdWMzUnpMbTFwWTNKdmMyOW1kQzVqYjIwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURGS2xzVkdYVjlKRk9kVUpPcDQ5emJjSTFVdHl3TUZwNFZyN0RWRFlqemxFazhnRjh3VUpGaHFPYzU2b1pVMGpLQm9BV2tDMHNlZnBmWG1kYXpiN1lzQ0ZqcFVaL3BXZWwwaU5zbURIaUFsK3l0ZnloeWkrQm5rQ0pDckNUSmlhSzJWTnAwUWdZSEpsNktwcFZZRld1QXIzVVZoeUd0Q3hjb1pydVlMQmxiN1VOMlQ2QWJSM2E2V0toRDU4UlJBRGE0RWJlY0NvbjZNdFZ2OUFlUWRpK2l6SzdoaElHZWc1Q1BNdUlFTzAyZCtLZ0FyTGxYQURtM0pPNWllL0p0bm9QU01zQ0FoSlFHcUt4amEyOElsSjRWb3JNalR1VjVsNzB4N1ZVVkJnMkVJZ3ArdmdKOEY1MUtYUGJRS3VKdnlYU0NMRWwrZmY3dFBqRmhpMmkzZ0UvSkFnTUJBQUdqZ2dRWE1JSUVFekNDQVgwR0Npc0dBUVFCMW5rQ0JBSUVnZ0Z0QklJQmFRRm5BSFVBVG5XakoxeWFFTU00VzJ6VTN6OVM2eDN3NEk0YmpXbkFzZnBrc1dLYU9kOEFBQUdORTRTRzFnQUFCQU1BUmpCRUFpQXFYRzNVdFNibGkzZVlVSWxOazhTSVFZVTVKZHhRa2N6b25Pa2FwK2MzT2dJZ01ZMnBaR0JncjdXZEFRQTUwREJUaDhVN09pUTNkUHZtMUorVEp0Vmh4VW9BZGdCOVdSNFM0WGdxZXh4aFozeGUvZmpRaDF3VW9FNlZucmtETDlrT2pDNTV1QUFBQVkwVGhJYXNBQUFFQXdCSE1FVUNJRXJpV0V0Y0tJekNtbTgzTFpLOW03cUg3VXBxVXk4UU1Ld1p0Ty82Mmk2c0FpRUFnNzBBVXNHaE5QYXJBLzVnUE9rTnBNYVd2SWxiN0xqNDlYSXdEUFdyN1ZFQWRnQlZnZFRDRnBBMkFVcnFDNXRYUEZQd3dPUTRlSEFsQ0Jjdm82b2RCeFBUREFBQUFZMFRoSWluQUFBRUF3QkhNRVVDSVFEWEltb0RJaWRIOXBxdFpWcmtQWGJ6MnBhakttaFZ0bEpGOXpPRDhmN0hYZ0lnYVlYOVhjbW5QU3FtajZBZDBqK25CMWYxS0dhb3Uzd2IrQUhJZkE0ZXpBRXdKd1lKS3dZQkJBR0NOeFVLQkJvd0dEQUtCZ2dyQmdFRkJRY0RBakFLQmdnckJnRUZCUWNEQVRBOEJna3JCZ0VFQVlJM0ZRY0VMekF0QmlVckJnRUVBWUkzRlFpSHZkY2JnZWZyUm9LQm5TNk8wQXlIOE5vZFhZS0U1V21DODZjK0FnRmtBZ0VtTUlHMEJnZ3JCZ0VGQlFjQkFRU0JwekNCcERCekJnZ3JCZ0VGQlFjd0FvWm5hSFIwY0RvdkwzZDNkeTV0YVdOeWIzTnZablF1WTI5dEwzQnJhVzl3Y3k5alpYSjBjeTlOYVdOeWIzTnZablFsTWpCQmVuVnlaU1V5TUZKVFFTVXlNRlJNVXlVeU1FbHpjM1ZwYm1jbE1qQkRRU1V5TURBMEpUSXdMU1V5TUhoemFXZHVMbU55ZERBdEJnZ3JCZ0VGQlFjd0FZWWhhSFIwY0RvdkwyOXVaVzlqYzNBdWJXbGpjbTl6YjJaMExtTnZiUzl2WTNOd01CMEdBMVVkRGdRV0JCUVdzdG4vTkhNdzhCMDJzZ0xOY0FMWnhLTU5NVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdJUVlEVlIwUkJCb3dHSUlXYlhObWRDNXpkSE11YldsamNtOXpiMlowTG1OdmJUQU1CZ05WSFJNQkFmOEVBakFBTUdvR0ExVWRId1JqTUdFd1g2QmRvRnVHV1doMGRIQTZMeTkzZDNjdWJXbGpjbTl6YjJaMExtTnZiUzl3YTJsdmNITXZZM0pzTDAxcFkzSnZjMjltZENVeU1FRjZkWEpsSlRJd1VsTkJKVEl3VkV4VEpUSXdTWE56ZFdsdVp5VXlNRU5CSlRJd01EUXVZM0pzTUdZR0ExVWRJQVJmTUYwd1VRWU1Ld1lCQkFHQ04weURmUUVCTUVFd1B3WUlLd1lCQlFVSEFnRVdNMmgwZEhBNkx5OTNkM2N1YldsamNtOXpiMlowTG1OdmJTOXdhMmx2Y0hNdlJHOWpjeTlTWlhCdmMybDBiM0o1TG1oMGJUQUlCZ1puZ1F3QkFnSXdId1lEVlIwakJCZ3dGb0FVTzNEUlUrbDJKWjFncU1wbUQ4YWJybTlVRm1vd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3SUdDQ3NHQVFVRkJ3TUJNQTBHQ1NxR1NJYjNEUUVCREFVQUE0SUNBUUFFMjlNWDF2WWRXU2xKV3Q4UGlydDhXVGdJanVLSkFmMW9yTE9vM1NQMjdtbHJiNlByQWZtVExYN1VTOG5taVc2bVpGMjl4Vzhnb3ZmWkJNczZ3MFh4d2o3Wjl3RlA2aDhYQ1MvMzh2UkhQZkVTMFBnVkhpUTRYNU41Z0R2azlRQVNXU3RuVzhqVWhaLzFmQ0l3c0Y2dFQ3UnJkM1M3OWFVRjhGRVdWL3M1U0tFM2d1N1BrVzkxQlQ0NG5GcTF6ejNjaWw1Qjc2OEQ0TTBJcDlkY3VaK3RlamtiUGtXVndGaHY2dmx3V3lTeXJ1SUlaNU1lRHpoYUpEaFZqSEQ3V2lGMys2aVVoRUl3T05FM0poVVNSTDF0UjZpZmJGeGhKd1R4b1FtNkxMN21DY3FkRkdGZnNoUlF4OTcxN3RQcFIwbEdWZ3FuWXhsQnd2MmxTZ3pobCttV2p5NEM4dHpnS3RoZ05CaFk1bjdSbWw1RkFqZkE2Y1VQUWg2MHdzMzBBZFNhS0RaOGtWTTFxTEtVb0FkNWhqQi9ad0hGTkZvWVFncjFiZ1Rjc3lsdzRBKzN3dUpPNmYvcjRmWnVvaDNUSmppbDI5MFhGZ3ZwNzZvTGVNeFg3em9uVzNIU2IvY05UZUZMTmVGM3NVYnVRUzBoeE16d25qNmpqSXpGSnhhczU0SlpycGtydjJYcHR6RHZiZWVnM29OQVJHdEc0TkY0TkFmYVRWL2M0QXJHeHRnUWw0V3hlYlU1VXo5UnY5V2tmbEo0bkFpL0RreC85ZGJuUWk3VmtUN2ZCdDBidnI5SGFiNkdmWjYyR3RsRWc2ZWlaNWI4WmlOSFBiMzVIV0tYS0RObnBXb2ljWCtsbVdqZkdBWXRkY1M2NERYM2dtVzN4c28vN1dlNkVLUjNidz09PC9YNTA5Q2VydGlmaWNhdGU+PC9YNTA5RGF0YT48L0tleUluZm8+PC9kczpTaWduYXR1cmU+PC9zYW1sOkFzc2VydGlvbj4=
            client_id:
                - '[REDACTED]'
            client_info:
                - "1"
            grant_type:
                - urn:ietf:params:oauth:grant-type:saml1_1-bearer
            password:
                - '[REDACTED]'
            req_cnf:
                - '[REDACTED]'
            scope:
                - '6dae42f8-4368-4678-94ff-3960e28e3630/.default openid offline_access profile'
            token_type:
                - pop
            username:
                - USERNAME
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - ccb6d130-1f77-495d-b371-3f785ac3cdb6
            Content-Type:
                - application/x-www-form-urlencoded; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token
        method: POST
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 4946
        uncompressed: false
        body: '{"token_type":"Bearer","expires_in":86399,"ext_expires_in":86399,"access_token":"TEST_ACCESS_TOKEN"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - ccb6d130-1f77-495d-b371-3f785ac3cdb6
            Content-Length:
                - "4946"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 21 Feb 2024 21:14:28 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Clitelem:
                - 1,0,0,,
            X-Ms-Ests-Server:
                - 2.1.17396.6 - EUS ProdSlices
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 460.493814ms
07070100000069000081A4000000000000000000000001687816E5000026C9000000000000000000000000000000000000005C00000000kubelogin-0.2.10/pkg/internal/pop/testdata/AcquirePoPTokenConfidentialFromBadSecretVCR.yaml---
version: 2
interactions:
    - id: 0
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - be8c850b-0a27-4a34-bb09-9c47caa68378
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=https%3A%2F%2Flogin.microsoftonline.com%2F00000000-0000-0000-0000-000000000000%2Foauth2%2Fv2.0%2Fauthorize
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 980
        uncompressed: false
        body: '{"tenant_discovery_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - be8c850b-0a27-4a34-bb09-9c47caa68378
            Content-Length:
                - "980"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Fri, 01 Sep 2023 00:04:12 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.16150.3 - SCUS ProdSlices
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 251.892272ms
    - id: 1
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 179f7bc3-d530-4b6c-a573-a60bded5a3cd
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 1753
        uncompressed: false
        body: '{"token_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 179f7bc3-d530-4b6c-a573-a60bded5a3cd
            Content-Length:
                - "1753"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Fri, 01 Sep 2023 00:04:13 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.16209.3 - EUS ProdSlices
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 89.482682ms
    - id: 2
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 300
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: client_id=[REDACTED]&client_secret=Bad_Secret&grant_type=client_credentials&req_cnf=[REDACTED]&scope=6256c85f-0aad-4d50-b960-e6e9b21efe35%2F.default+openid+offline_access+profile&token_type=pop
        form:
            client_id:
                - '[REDACTED]'
            client_secret:
                - Bad_Secret
            grant_type:
                - client_credentials
            req_cnf:
                - '[REDACTED]'
            scope:
                - '6dae42f8-4368-4678-94ff-3960e28e3630/.default openid offline_access profile'
            token_type:
                - pop
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 4a139f54-91e6-483a-ab79-25451bd3479f
            Content-Type:
                - application/x-www-form-urlencoded; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token
        method: POST
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 632
        uncompressed: false
        body: '{"error":"invalid_client","error_description":"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app ''''[REDACTED]''''.\r\nTrace ID: [REDACTED]\r\nCorrelation ID: [REDACTED]\r\nTimestamp: 2023-06-02 21:00:26Z","error_codes":[7000215],"timestamp":"2023-06-02 21:00:26Z","trace_id":"[REDACTED]","correlation_id":"[REDACTED]","error_uri":"https://login.microsoftonline.com/error?code=7000215"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - 4a139f54-91e6-483a-ab79-25451bd3479f
            Content-Length:
                - "632"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Fri, 01 Sep 2023 00:04:13 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Clitelem:
                - 1,7000215,0,,
            X-Ms-Ests-Server:
                - 2.1.16209.3 - EUS ProdSlices
            X-Xss-Protection:
                - "0"
        status: 401 Unauthorized
        code: 401
        duration: 175.229239ms
0707010000006A000081A4000000000000000000000001687816E500002525000000000000000000000000000000000000005900000000kubelogin-0.2.10/pkg/internal/pop/testdata/AcquirePoPTokenConfidentialWithSecretVCR.yaml---
version: 2
interactions:
    - id: 0
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 065e28b0-f783-4c75-8e2c-e4dc665742d2
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=https%3A%2F%2Flogin.microsoftonline.com%2F00000000-0000-0000-0000-000000000000%2Foauth2%2Fv2.0%2Fauthorize
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 980
        uncompressed: false
        body: '{"tenant_discovery_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 065e28b0-f783-4c75-8e2c-e4dc665742d2
            Content-Length:
                - "980"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Fri, 01 Sep 2023 00:07:59 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.16150.3 - EUS ProdSlices
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 262.893349ms
    - id: 1
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 4e0b4541-609a-48ee-91ec-e77d961ef56d
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 1753
        uncompressed: false
        body: '{"token_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 4e0b4541-609a-48ee-91ec-e77d961ef56d
            Content-Length:
                - "1753"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Fri, 01 Sep 2023 00:07:59 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.16209.3 - EUS ProdSlices
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 91.482757ms
    - id: 2
      request:
        proto: ""
        proto_major: 0
        proto_minor: 0
        content_length: 330
        transfer_encoding: []
        trailer: {}
        host: ""
        remote_addr: ""
        request_uri: ""
        body: client_id=[REDACTED]&client_secret=[REDACTED]&grant_type=client_credentials&req_cnf=[REDACTED]&scope=6256c85f-0aad-4d50-b960-e6e9b21efe35%2F.default+openid+offline_access+profile&token_type=pop
        form:
            client_id:
                - '[REDACTED]'
            client_secret:
                - '[REDACTED]'
            grant_type:
                - client_credentials
            req_cnf:
                - '[REDACTED]'
            scope:
                - '6dae42f8-4368-4678-94ff-3960e28e3630/.default openid offline_access profile'
            token_type:
                - pop
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 0e0789fc-d6fd-4157-a622-d5da8347b009
            Content-Type:
                - application/x-www-form-urlencoded; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token
        method: POST
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 1475
        uncompressed: false
        body: '{"token_type":"Bearer","expires_in":86399,"ext_expires_in":86399,"access_token":"TEST_ACCESS_TOKEN"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - 0e0789fc-d6fd-4157-a622-d5da8347b009
            Content-Length:
                - "1475"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Fri, 01 Sep 2023 00:07:59 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Clitelem:
                - 1,0,0,,
            X-Ms-Ests-Server:
                - 2.1.16209.3 - SCUS ProdSlices
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 157.469883ms
0707010000006B000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002800000000kubelogin-0.2.10/pkg/internal/testutils0707010000006C000081A4000000000000000000000001687816E50000209B000000000000000000000000000000000000003600000000kubelogin-0.2.10/pkg/internal/testutils/govcrutils.gopackage testutils

import (
	"encoding/json"
	"net/http"
	"regexp"
	"strings"

	"gopkg.in/dnaeon/go-vcr.v4/pkg/cassette"
	"gopkg.in/dnaeon/go-vcr.v4/pkg/recorder"
)

const (
	redactedToken = "[REDACTED]"
	TestToken     = "TEST_ACCESS_TOKEN"
	TestUsername  = "user@example.com"
	TestTenantID  = "00000000-0000-0000-0000-000000000000"
	TestClientID  = "80faf920-1908-4b52-b5ef-a8e7bedfc67a"
	TestServerID  = "6dae42f8-4368-4678-94ff-3960e28e3630"
)

const (
	mockClientInfo = "eyJ1aWQiOiJjNzNjNmYyOC1hZTVmLTQxM2QtYTlhMi1lMTFlNWFmNjY4ZjgiLCJ1dGlkIjoiZTBiZDIzMjEtMDdmYS00Y2YwLTg3YjgtMDBhYTJhNzQ3MzI5In0"
	mockIDT        = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Imwzc1EtNTBjQ0g0eEJWWkxIVEd3blNSNzY4MCJ9.eyJhdWQiOiIwNGIwNzc5NS04ZGRiLTQ2MWEtYmJlZS0wMmY5ZTFiZjdiNDYiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vYzU0ZmFjODgtM2RkMy00NjFmLWE3YzQtOGEzNjhlMDM0MGIzL3YyLjAiLCJpYXQiOjE2MzcxOTEyMTIsIm5iZiI6MTYzNzE5MTIxMiwiZXhwIjoxNjM3MTk1MTEyLCJhaW8iOiJBVVFBdS84VEFBQUFQMExOZGNRUXQxNmJoSkFreXlBdjFoUGJuQVhtT0o3RXJDVHV4N0hNTjhHd2VMb2FYMWR1cDJhQ2Y0a0p5bDFzNmovSzF5R05DZmVIQlBXM21QUWlDdz09IiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvZTBiZDIzMjEtMDdmYS00Y2YwLTg3YjgtMDBhYTJhNzQ3MzI5LyIsIm5hbWUiOiJJZGVudGl0eSBUZXN0IFVzZXIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJpZGVudGl0eXRlc3R1c2VyQGF6dXJlc2Rrb3V0bG9vay5vbm1pY3Jvc29mdC5jb20iLCJyaCI6IjAuQVMwQWlLeFB4ZE05SDBhbnhJbzJqZ05BczVWM3NBVGJqUnBHdS00Qy1lR19lMFl0QUxFLiIsInN1YiI6ImMxYTBsY2xtbWxCYW9wc0MwVmlaLVpPMjFCT2dSUXE3SG9HRUtOOXloZnMiLCJ0aWQiOiJjNTRmYWM4OC0zZGQzLTQ2MWYtYTdjNC04YTM2OGUwMzQwYjMiLCJ1dGkiOiI5TXFOSWI5WjdrQy1QVHRtai11X0FBIiwidmVyIjoiMi4wIn0.hh5Exz9MBjTXrTuTZnz7vceiuQjcC_oRSTeBIC9tYgSO2c2sqQRpZi91qBZFQD9okayLPPKcwqXgEJD9p0-c4nUR5UQN7YSeDLmYtZUYMG79EsA7IMiQaiy94AyIe2E-oBDcLwFycGwh1iIOwwOwjbanmu2Dx3HfQx831lH9uVjagf0Aow0wTkTVCsedGSZvG-cRUceFLj-kFN-feFH3NuScuOfLR2Magf541pJda7X7oStwL_RNUFqjJFTdsiFV4e-VHK5qo--3oPU06z0rS9bosj0pFSATIVHrrS4gY7jiSvgMbG837CDBQkz5b08GUN5GlLN9jlygl1plBmbgww"
)

var emailRegex = regexp.MustCompile(`[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}`)

func GetVCRHttpClient(path, tenantID string) (*recorder.Recorder, error) {
	deviceCodePendingCount := 0
	beforeSaveHook := func(i *cassette.Interaction) error {
		// in device code login, since the client polls for the completion of the login
		// we only record it once to speed up the replay
		if strings.Contains(i.Response.Body, "AADSTS70016") {
			if deviceCodePendingCount > 0 {
				i.DiscardOnSave = true
				return nil
			}
			deviceCodePendingCount++
		}
		var detectedClientID,
			detectedClientSecret,
			detectedClientAssertion,
			detectedScope,
			detectedReqCnf,
			detectedPassword,
			detectedUsername,
			detectedDeviceCode string
		// Delete sensitive content
		delete(i.Response.Headers, "Set-Cookie")
		delete(i.Response.Headers, "X-Ms-Request-Id")
		if i.Request.Form["client_id"] != nil {
			detectedClientID = i.Request.Form["client_id"][0]
			i.Request.Form["client_id"] = []string{redactedToken}
		}
		if i.Request.Form["client_secret"] != nil && i.Request.Form["client_secret"][0] != BadSecret {
			detectedClientSecret = i.Request.Form["client_secret"][0]
			i.Request.Form["client_secret"] = []string{redactedToken}
		}
		if i.Request.Form["client_assertion"] != nil {
			detectedClientAssertion = i.Request.Form["client_assertion"][0]
			i.Request.Form["client_assertion"] = []string{redactedToken}
		}
		if i.Request.Form["req_cnf"] != nil {
			detectedScope = i.Request.Form["req_cnf"][0]
			i.Request.Form["req_cnf"] = []string{redactedToken}
		}
		if i.Request.Form["password"] != nil && i.Request.Form["password"][0] != BadSecret {
			detectedPassword = i.Request.Form["password"][0]
			i.Request.Form["password"] = []string{redactedToken}
		}
		if i.Request.Form["username"] != nil {
			detectedUsername = i.Request.Form["username"][0]
			i.Request.Form["username"] = []string{redactedToken}
		}
		if i.Request.Form["device_code"] != nil {
			detectedDeviceCode = i.Request.Form["device_code"][0]
			i.Request.Form["device_code"] = []string{redactedToken}
		}

		i.Request.URL = redactURL(i.Request.URL, tenantID)
		i.Response.Body = strings.ReplaceAll(i.Response.Body, tenantID, TestTenantID)

		if detectedClientID != "" {
			i.Request.Body = strings.ReplaceAll(i.Request.Body, detectedClientID, redactedToken)
		}
		if detectedClientSecret != "" {
			i.Request.Body = ReplaceSecretValuesIncludingURLEscaped(i.Request.Body, detectedClientSecret, redactedToken)
		}
		if detectedClientAssertion != "" {
			i.Request.Body = strings.ReplaceAll(i.Request.Body, detectedClientAssertion, redactedToken)
		}
		if detectedScope != "" {
			i.Request.Body = strings.ReplaceAll(i.Request.Body, detectedScope, redactedToken)
		}
		if detectedReqCnf != "" {
			i.Request.Body = strings.ReplaceAll(i.Request.Body, detectedReqCnf, redactedToken)
		}
		if detectedPassword != "" {
			i.Request.Body = ReplaceSecretValuesIncludingURLEscaped(i.Request.Body, detectedPassword, redactedToken)
		}
		if detectedUsername != "" {
			i.Request.Body = ReplaceSecretValuesIncludingURLEscaped(i.Request.Body, detectedUsername, TestUsername)
			i.Request.URL = ReplaceSecretValuesIncludingURLEscaped(i.Request.URL, detectedUsername, TestUsername)
		}
		if detectedDeviceCode != "" {
			i.Request.Body = strings.ReplaceAll(i.Request.Body, detectedDeviceCode, redactedToken)
		}

		if strings.Contains(i.Response.Body, "access_token") || strings.Contains(i.Response.Body, "device_code") {
			redacted, err := redactToken(i.Response.Body)
			if err != nil {
				return err
			}
			i.Response.Body = redacted
		}

		if strings.Contains(i.Response.Body, "Invalid client secret provided") {
			i.Response.Body = `{"error":"invalid_client","error_description":"AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app ''[REDACTED]''.\r\nTrace ID: [REDACTED]\r\nCorrelation ID: [REDACTED]\r\nTimestamp: 2023-06-02 21:00:26Z","error_codes":[7000215],"timestamp":"2023-06-02 21:00:26Z","trace_id":"[REDACTED]","correlation_id":"[REDACTED]","error_uri":"https://login.microsoftonline.com/error?code=7000215"}`
		}
		return nil
	}

	playbackHook := func(i *cassette.Interaction) error {
		if strings.Contains(i.Response.Body, "access_token") {
			redacted, err := redactToken(i.Response.Body)
			if err != nil {
				return err
			}
			i.Response.Body = redacted
		}
		return nil
	}

	matcher := func(r *http.Request, i cassette.Request) bool {
		url := redactURL(r.URL.String(), tenantID)
		if r.Method != i.Method || url != i.URL {
			return false
		}
		_ = r.ParseForm()
		requestFormValues := r.Form
		isPop := i.Form["token_type"] != nil && i.Form["token_type"][0] == "pop"

		for k, v := range i.Form {
			if requestFormValues[k][0] != v[0] {
				// if recorded value is redaction token and request value is empty, then it is a mismatch
				if v[0] == redactedToken {
					if len(requestFormValues[k][0]) == 0 {
						return false
					}
					continue
				}
				// saml assertion is not relevant for the test
				if isPop && k == "assertion" {
					continue
				}
				return false
			}
		}

		return true
	}

	recOpts := []recorder.Option{
		recorder.WithHook(beforeSaveHook, recorder.BeforeSaveHook),
		recorder.WithHook(playbackHook, recorder.BeforeResponseReplayHook),
		recorder.WithMatcher(matcher),
		recorder.WithSkipRequestLatency(true),
	}

	return recorder.New(path, recOpts...)
}

func redactURL(url, tenantID string) string {
	if strings.Contains(url, "UserRealm") {
		url = emailRegex.ReplaceAllString(url, TestUsername)
	}
	return strings.ReplaceAll(url, tenantID, TestTenantID)
}

func redactToken(body string) (string, error) {
	var data map[string]interface{}
	err := json.Unmarshal([]byte(body), &data)
	if err != nil {
		return "", err
	}

	if _, ok := data["access_token"]; ok {
		data["access_token"] = TestToken
	}

	if _, ok := data["refresh_token"]; ok {
		data["refresh_token"] = TestToken
	}

	if _, ok := data["id_token"]; ok {
		data["id_token"] = mockIDT
	}

	if _, ok := data["client_info"]; ok {
		data["client_info"] = mockClientInfo
	}

	if _, ok := data["device_code"]; ok {
		data["device_code"] = redactedToken
	}

	// Marshal the map back to a JSON string
	redactedJSON, err := json.Marshal(data)
	if err != nil {
		return "", err
	}

	return string(redactedJSON), nil
}
0707010000006D000081A4000000000000000000000001687816E5000005DE000000000000000000000000000000000000003500000000kubelogin-0.2.10/pkg/internal/testutils/testutils.gopackage testutils

import (
	"net/url"
	"strings"
)

const (
	ClientID       = "AZURE_CLIENT_ID"
	ClientSecret   = "AAD_SERVICE_PRINCIPAL_CLIENT_SECRET"
	ClientCert     = "AZURE_CLIENT_CER"
	ClientCertPass = "AZURE_CLIENT_CERTIFICATE_PASSWORD"
	ResourceID     = "AZURE_RESOURCE_ID"
	TenantID       = "AZURE_TENANT_ID"
	BadSecret      = "Bad_Secret"
	Username       = "USERNAME"
	Password       = "PASSWORD"
)

// ErrorContains takes an input error and a desired substring, checks if the string is present
// in the error message, and returns the boolean result
func ErrorContains(out error, want string) bool {
	substring := strings.TrimSpace(want)
	if out == nil {
		return substring == ""
	}
	if substring == "" {
		return false
	}
	return strings.Contains(out.Error(), substring)
}

// ReplaceSecretValuesIncludingURLEscaped takes an input string, finds any instances of the
// input secret in the string (including in URL-escaped format), and replaces all instances
// with the given redaction token
// This is used for VCR tests as they sometimes include a URL-escaped version of the secret
// in the request body
func ReplaceSecretValuesIncludingURLEscaped(body, secret, redactionToken string) string {
	body = strings.ReplaceAll(body, secret, redactionToken)
	// get the URL-escaped version of the secret which replaces special characters with
	// the URL-safe "%AB" format
	escapedSecret := url.QueryEscape(secret)
	body = strings.ReplaceAll(body, escapedSecret, redactionToken)
	return body
}
0707010000006E000081A4000000000000000000000001687816E500000E0D000000000000000000000000000000000000003A00000000kubelogin-0.2.10/pkg/internal/testutils/testutils_test.gopackage testutils

import (
	"fmt"
	"testing"
)

func TestErrorContains(t *testing.T) {
	testCase := []struct {
		name             string
		err              error
		desiredSubstring string
		expectedResult   bool
	}{
		{
			name:             "should return true if error is nil and desired substring is empty string",
			desiredSubstring: "",
			err:              nil,
			expectedResult:   true,
		},
		{
			name:             "should return true if error is nil and desired substring is whitespace",
			desiredSubstring: "		   ",
			err:              nil,
			expectedResult:   true,
		},
		{
			name:             "should return false if error is not nil and desired substring is empty string",
			desiredSubstring: "",
			err:              fmt.Errorf("test error"),
			expectedResult:   false,
		},
		{
			name:             "should return false if error is not nil and desired substring is whitespace",
			desiredSubstring: "	   		",
			err:              fmt.Errorf("test error"),
			expectedResult:   false,
		},
		{
			name:             "should return false if error is not nil and desired substring is not contained in error",
			desiredSubstring: "not a test error",
			err:              fmt.Errorf("test error"),
			expectedResult:   false,
		},
		{
			name:             "should return true if error is not nil and desired substring is smaller than but contained in error",
			desiredSubstring: "error",
			err:              fmt.Errorf("test error"),
			expectedResult:   true,
		},
		{
			name:             "should return true if error is not nil and desired substring is the same as error string",
			desiredSubstring: "test error",
			err:              fmt.Errorf("test error"),
			expectedResult:   true,
		},
		{
			name:             "should return false if error is not nil and desired substring is the same as error string but has different casing",
			desiredSubstring: "Test Error",
			err:              fmt.Errorf("test error"),
			expectedResult:   false,
		},
	}

	for _, tc := range testCase {
		t.Run(tc.name, func(t *testing.T) {
			result := ErrorContains(tc.err, tc.desiredSubstring)
			if result != tc.expectedResult {
				t.Errorf(
					"comparing error: %s and desired substring: %s, expected %t but got %t",
					tc.err,
					tc.desiredSubstring,
					tc.expectedResult,
					result,
				)
			}
		})
	}
}

func TestReplaceSecretValuesIncludingURLEscaped(t *testing.T) {
	testCase := []struct {
		name           string
		body           string
		secret         string
		expectedResult string
	}{
		{
			name:           "TestReplaceMultipleSecretValuesWithNonEscapedString",
			body:           "This is a test request body. ABC123. This is the rest of the request body. ThisABC123 is another line.",
			secret:         "ABC123",
			expectedResult: "This is a test request body. [REDACTED]. This is the rest of the request body. This[REDACTED] is another line.",
		},
		{
			name:           "TestReplaceMultipleSecretValuesWithStringEscape",
			body:           "This is a test request body. Q#4@6:=. This is the rest of the request body. ThisQ%234%406%3A%3D is another line.",
			secret:         "Q#4@6:=",
			expectedResult: "This is a test request body. [REDACTED]. This is the rest of the request body. This[REDACTED] is another line.",
		},
	}

	for _, tc := range testCase {
		t.Run(tc.name, func(t *testing.T) {
			result := ReplaceSecretValuesIncludingURLEscaped(tc.body, tc.secret, redactedToken)
			if result != tc.expectedResult {
				t.Errorf(
					"expected redaction of secret as \n%s\n but got \n%s\n",
					tc.expectedResult,
					result,
				)
			}
		})
	}
}
0707010000006F000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002400000000kubelogin-0.2.10/pkg/internal/token07070100000070000081A4000000000000000000000001687816E5000006BF000000000000000000000000000000000000002E00000000kubelogin-0.2.10/pkg/internal/token/README.MDInstruction for recording response using [GO-VCR](https://github.com/dnaeon/go-vcr) for unit test
# Things to know if you want to record new recording
* All the recorded responses have been saved under folder `/testdata`

* Highly recommand using `RecordOnly` if you want completely new recording, otherwise, current recordings have been modified without the sensitive contents
* Here's the variable you need to input for recording 
Modify these variables 
modify authorizer clientID `AZURE_CLIENT_ID="<specify with real value>"`
modify authorizer clientSecret `AAD_SERVICE_PRINCIPAL_CLIENT_SECRET="<specify with real value>" `
modify authorizer clientCert `AZURE_CLIENT_CER="<specify with real value>"`
modify authorizer clientCertPass `AZURE_CLIENT_CERTIFICATE_PASSWORD="<specify with real value>" `
modify authorizer resourceID `AZURE_RESOURCE_ID="<specify with real value>"`
modify authorizer tenantID `AZURE_TENANT_ID="<specify with real value>" `
modify go-vcr record mode `VCR_MODE="<specify vcr mode>" `
you can set to record mode by setting vcr mode to RecordOnly `VCR_MODE="RecordOnly"`
To return to replay mode, simply unset the enviroment variable by `unset VCR_MODE`

Examples: 
# Recording Mode
* Navigate to `pkg/token` folder in terminal
* Setup your enviroment variables

```
export AZURE_CLIENT_ID="<specify with real value>"
export AAD_SERVICE_PRINCIPAL_CLIENT_SECRET="<specify with real value>"
export AZURE_CLIENT_CER="<specify with real value>"
export AZURE_CLIENT_CERTIFICATE_PASSWORD="<specify with real value>"
export AZURE_RESOURCE_ID="<specify with real value>"
export AZURE_TENANT_ID="<specify with real value>"
export VCR_MODE="RecordOnly"
go test
```

# Replay Mode
```
unset VCR_MODE
go test
```
07070100000071000081A4000000000000000000000001687816E500000ACB000000000000000000000000000000000000004000000000kubelogin-0.2.10/pkg/internal/token/adalclientcertcredential.gopackage token

import (
	"context"
	"fmt"
	"strings"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/go-autorest/autorest/adal"
)

type ADALClientCertCredential struct {
	oAuthConfig        adal.OAuthConfig
	clientID           string
	clientCert         string
	clientCertPassword string
}

var _ CredentialProvider = (*ADALClientCertCredential)(nil)

func newADALClientCertCredential(opts *Options) (CredentialProvider, error) {
	if !opts.IsLegacy {
		return nil, fmt.Errorf("ADALClientCertCredential is not supported in non-legacy mode")
	}
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	if opts.ClientCert == "" {
		return nil, fmt.Errorf("client certificate cannot be empty")
	}
	cloud := opts.GetCloudConfiguration()
	oAuthConfig, err := adal.NewOAuthConfig(cloud.ActiveDirectoryAuthorityHost, opts.TenantID)
	if err != nil {
		return nil, fmt.Errorf("failed to create OAuth config: %w", err)
	}
	return &ADALClientCertCredential{
		oAuthConfig:        *oAuthConfig,
		clientID:           opts.ClientID,
		clientCert:         opts.ClientCert,
		clientCertPassword: opts.ClientCertPassword,
	}, nil
}

func (c *ADALClientCertCredential) Name() string {
	return "ADALClientCertCredential"
}

func (c *ADALClientCertCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *ADALClientCertCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	// Get the certificate and private key from cert file
	cert, rsaPrivateKey, err := readCertificate(c.clientCert, c.clientCertPassword)
	if err != nil {
		return azcore.AccessToken{}, fmt.Errorf("failed to read certificate: %w", err)
	}

	// to keep backward compatibility,
	// 1. we only support one resource
	// 2. we remove the "/.default" suffix from the resource
	resource := strings.Replace(opts.Scopes[0], "/.default", "", 1)
	spt, err := adal.NewServicePrincipalTokenFromCertificate(
		c.oAuthConfig,
		c.clientID,
		cert,
		rsaPrivateKey,
		resource)
	if err != nil {
		return azcore.AccessToken{}, fmt.Errorf("failed to create service principal token using secret: %w", err)
	}

	if err := spt.EnsureFreshWithContext(ctx); err != nil {
		return azcore.AccessToken{}, err
	}

	token := spt.Token()
	return azcore.AccessToken{Token: token.AccessToken, ExpiresOn: token.Expires()}, nil
}

func (c *ADALClientCertCredential) NeedAuthenticate() bool {
	return false
}
07070100000072000081A4000000000000000000000001687816E500000855000000000000000000000000000000000000004500000000kubelogin-0.2.10/pkg/internal/token/adalclientcertcredential_test.gopackage token

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewADALClientCertCredential(t *testing.T) {
	testCases := []struct {
		name           string
		opts           *Options
		expectErrorMsg string
		expectName     string
	}{
		{
			name: "valid options",
			opts: &Options{
				ClientID:           "test-client-id",
				TenantID:           "test-tenant-id",
				ClientCert:         "test-cert-path",
				ClientCertPassword: "test-cert-password",
				IsLegacy:           true,
			},
			expectName: "ADALClientCertCredential",
		},
		{
			name: "missing client ID",
			opts: &Options{
				TenantID:           "test-tenant-id",
				ClientCert:         "test-cert-path",
				ClientCertPassword: "test-cert-password",
				IsLegacy:           true,
			},
			expectErrorMsg: "client ID cannot be empty",
		},
		{
			name: "missing tenant ID",
			opts: &Options{
				ClientID:           "test-client-id",
				ClientCert:         "test-cert-path",
				ClientCertPassword: "test-cert-password",
				IsLegacy:           true,
			},
			expectErrorMsg: "tenant ID cannot be empty",
		},
		{
			name: "missing client certificate",
			opts: &Options{
				ClientID:           "test-client-id",
				TenantID:           "test-tenant-id",
				ClientCertPassword: "test-cert-password",
				IsLegacy:           true,
			},
			expectErrorMsg: "client certificate cannot be empty",
		},
		{
			name: "non-legacy mode",
			opts: &Options{
				ClientID:           "test-client-id",
				TenantID:           "test-tenant-id",
				ClientCert:         "test-cert-path",
				ClientCertPassword: "test-cert-password",
				IsLegacy:           false,
			},
			expectErrorMsg: "ADALClientCertCredential is not supported in non-legacy mode",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			cred, err := newADALClientCertCredential(tc.opts)
			if tc.expectErrorMsg != "" {
				assert.Error(t, err)
				assert.Equal(t, tc.expectErrorMsg, err.Error())
				assert.Nil(t, cred)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, cred)
				assert.Equal(t, tc.expectName, cred.Name())
			}
		})
	}
}
07070100000073000081A4000000000000000000000001687816E50000096C000000000000000000000000000000000000004200000000kubelogin-0.2.10/pkg/internal/token/adalclientsecretcredential.gopackage token

import (
	"context"
	"fmt"
	"strings"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/go-autorest/autorest/adal"
)

type ADALClientSecretCredential struct {
	oAuthConfig  adal.OAuthConfig
	clientID     string
	clientSecret string
}

var _ CredentialProvider = (*ADALClientSecretCredential)(nil)

func newADALClientSecretCredential(opts *Options) (CredentialProvider, error) {
	if !opts.IsLegacy {
		return nil, fmt.Errorf("ADALClientSecretCredential is not supported in non-legacy mode")
	}
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	if opts.ClientSecret == "" {
		return nil, fmt.Errorf("client secret cannot be empty")
	}
	cloud := opts.GetCloudConfiguration()
	oAuthConfig, err := adal.NewOAuthConfig(cloud.ActiveDirectoryAuthorityHost, opts.TenantID)
	if err != nil {
		return nil, fmt.Errorf("failed to create OAuth config: %w", err)
	}
	return &ADALClientSecretCredential{
		oAuthConfig:  *oAuthConfig,
		clientID:     opts.ClientID,
		clientSecret: opts.ClientSecret,
	}, nil
}

func (c *ADALClientSecretCredential) Name() string {
	return "ADALClientSecretCredential"
}

func (c *ADALClientSecretCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *ADALClientSecretCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	// to keep backward compatibility,
	// 1. we only support one resource
	// 2. we remove the "/.default" suffix from the resource
	resource := strings.Replace(opts.Scopes[0], "/.default", "", 1)
	spt, err := adal.NewServicePrincipalToken(
		c.oAuthConfig,
		c.clientID,
		c.clientSecret,
		resource)
	if err != nil {
		return azcore.AccessToken{}, fmt.Errorf("failed to create service principal token using secret: %w", err)
	}

	if err := spt.EnsureFreshWithContext(ctx); err != nil {
		return azcore.AccessToken{}, err
	}

	token := spt.Token()
	return azcore.AccessToken{Token: token.AccessToken, ExpiresOn: token.Expires()}, nil
}

func (c *ADALClientSecretCredential) NeedAuthenticate() bool {
	return false
}
07070100000074000081A4000000000000000000000001687816E50000070B000000000000000000000000000000000000004700000000kubelogin-0.2.10/pkg/internal/token/adalclientsecretcredential_test.gopackage token

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewADALClientSecretCredential(t *testing.T) {
	testCases := []struct {
		name           string
		opts           *Options
		expectErrorMsg string
		expectName     string
	}{
		{
			name: "valid options",
			opts: &Options{
				ClientID:     "test-client-id",
				TenantID:     "test-tenant-id",
				ClientSecret: "test-client-secret",
				IsLegacy:     true,
			},
			expectName: "ADALClientSecretCredential",
		},
		{
			name: "missing client ID",
			opts: &Options{
				TenantID:     "test-tenant-id",
				ClientSecret: "test-client-secret",
				IsLegacy:     true,
			},
			expectErrorMsg: "client ID cannot be empty",
		},
		{
			name: "missing tenant ID",
			opts: &Options{
				ClientID:     "test-client-id",
				ClientSecret: "test-client-secret",
				IsLegacy:     true,
			},
			expectErrorMsg: "tenant ID cannot be empty",
		},
		{
			name: "missing client secret",
			opts: &Options{
				ClientID: "test-client-id",
				TenantID: "test-tenant-id",
				IsLegacy: true,
			},
			expectErrorMsg: "client secret cannot be empty",
		},
		{
			name: "non-legacy mode",
			opts: &Options{
				ClientID:     "test-client-id",
				TenantID:     "test-tenant-id",
				ClientSecret: "test-client-secret",
				IsLegacy:     false,
			},
			expectErrorMsg: "ADALClientSecretCredential is not supported in non-legacy mode",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			cred, err := newADALClientSecretCredential(tc.opts)
			if tc.expectErrorMsg != "" {
				assert.Error(t, err)
				assert.Equal(t, tc.expectErrorMsg, err.Error())
				assert.Nil(t, cred)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, cred)
				assert.Equal(t, tc.expectName, cred.Name())
			}
		})
	}
}
07070100000075000081A4000000000000000000000001687816E5000009ED000000000000000000000000000000000000004000000000kubelogin-0.2.10/pkg/internal/token/adaldevicecodecredential.gopackage token

import (
	"context"
	"fmt"
	"os"
	"strings"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/go-autorest/autorest"
	"github.com/Azure/go-autorest/autorest/adal"
)

type ADALDeviceCodeCredential struct {
	oAuthConfig adal.OAuthConfig
	clientID    string
}

var _ CredentialProvider = (*ADALDeviceCodeCredential)(nil)

func newADALDeviceCodeCredential(opts *Options) (CredentialProvider, error) {
	if !opts.IsLegacy {
		return nil, fmt.Errorf("ADALDeviceCodeCredential is not supported in non-legacy mode")
	}
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	cloud := opts.GetCloudConfiguration()
	oAuthConfig, err := adal.NewOAuthConfig(cloud.ActiveDirectoryAuthorityHost, opts.TenantID)
	if err != nil {
		return nil, fmt.Errorf("failed to create OAuth config: %w", err)
	}
	return &ADALDeviceCodeCredential{
		oAuthConfig: *oAuthConfig,
		clientID:    opts.ClientID,
	}, nil
}

func (c *ADALDeviceCodeCredential) Name() string {
	return "ADALDeviceCodeCredential"
}

func (c *ADALDeviceCodeCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *ADALDeviceCodeCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	client := &autorest.Client{}
	// to keep backward compatibility,
	// 1. we only support one resource
	// 2. we remove the "/.default" suffix from the resource
	resource := strings.Replace(opts.Scopes[0], "/.default", "", 1)
	deviceCode, err := adal.InitiateDeviceAuth(client, c.oAuthConfig, c.clientID, resource)
	if err != nil {
		return azcore.AccessToken{}, fmt.Errorf("initialing the device code authentication: %w", err)
	}

	if _, err := fmt.Fprintln(os.Stderr, *deviceCode.Message); err != nil {
		return azcore.AccessToken{}, fmt.Errorf("prompting the device code message: %w", err)
	}

	token, err := adal.WaitForUserCompletionWithContext(ctx, client, deviceCode)
	if err != nil {
		return azcore.AccessToken{}, fmt.Errorf("waiting for device code authentication to complete: %w", err)
	}

	return azcore.AccessToken{Token: token.AccessToken, ExpiresOn: token.Expires()}, nil
}

func (c *ADALDeviceCodeCredential) NeedAuthenticate() bool {
	return false
}
07070100000076000081A4000000000000000000000001687816E500000500000000000000000000000000000000000000004500000000kubelogin-0.2.10/pkg/internal/token/adaldevicecodecredential_test.gopackage token

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewADALDeviceCodeCredential(t *testing.T) {
	testCases := []struct {
		name     string
		opts     *Options
		expected string
	}{
		{
			name: "valid options",
			opts: &Options{
				ClientID: "test-client-id",
				TenantID: "test-tenant-id",
				IsLegacy: true,
			},
			expected: "ADALDeviceCodeCredential",
		},
		{
			name: "missing client ID",
			opts: &Options{
				TenantID: "test-tenant-id",
				IsLegacy: true,
			},
			expected: "client ID cannot be empty",
		},
		{
			name: "missing tenant ID",
			opts: &Options{
				ClientID: "test-client-id",
				IsLegacy: true,
			},
			expected: "tenant ID cannot be empty",
		},
		{
			name: "non-legacy mode",
			opts: &Options{
				ClientID: "test-client-id",
				TenantID: "test-tenant-id",
				IsLegacy: false,
			},
			expected: "ADALDeviceCodeCredential is not supported in non-legacy mode",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			cred, err := newADALDeviceCodeCredential(tc.opts)
			if err != nil {
				assert.EqualError(t, err, tc.expected)
				assert.Nil(t, cred)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, cred)
				assert.Equal(t, tc.expected, cred.Name())
			}
		})
	}
}
07070100000077000081A4000000000000000000000001687816E5000003D3000000000000000000000000000000000000003C00000000kubelogin-0.2.10/pkg/internal/token/authenticationrecord.gopackage token

import (
	"encoding/json"
	"os"
	"path/filepath"

	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)

type CachedRecordProvider interface {
	// Retrieve reads the authentication record from the file.
	Retrieve() (azidentity.AuthenticationRecord, error)
	// Store writes the authentication record to the file.
	Store(record azidentity.AuthenticationRecord) error
}

type defaultCachedRecordProvider struct {
	file string
}

func (c *defaultCachedRecordProvider) Retrieve() (azidentity.AuthenticationRecord, error) {
	record := azidentity.AuthenticationRecord{}
	b, err := os.ReadFile(c.file)
	if err == nil {
		err = json.Unmarshal(b, &record)
	}
	return record, err
}

func (c *defaultCachedRecordProvider) Store(record azidentity.AuthenticationRecord) error {
	b, err := json.Marshal(record)
	if err != nil {
		return err
	}

	dir := filepath.Dir(c.file)
	if err := os.MkdirAll(dir, 0700); err != nil {
		return err
	}

	return os.WriteFile(c.file, b, 0600)
}
07070100000078000081A4000000000000000000000001687816E500000BA2000000000000000000000000000000000000004100000000kubelogin-0.2.10/pkg/internal/token/authenticationrecord_test.gopackage token

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/stretchr/testify/assert"
)

func TestDefaultCachedRecordProvider(t *testing.T) {
	testCases := []struct {
		name           string
		fileContent    string
		expectErrorMsg string
	}{
		{
			name:        "valid record",
			fileContent: `{"tenantID":"test-tenant-id","clientID":"test-client-id","authority":"https://login.microsoftonline.com/","homeAccountID":"test-home-account-id","username":"test-username","version":"1.0"}`,
		},
		{
			name:           "invalid JSON",
			fileContent:    `invalid-json-content`,
			expectErrorMsg: "invalid character",
		},
		{
			name:           "empty file",
			fileContent:    ``,
			expectErrorMsg: "unexpected end of JSON input",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			file, err := os.CreateTemp("", "test-record-*.json")
			assert.NoError(t, err)
			defer os.Remove(file.Name())

			_, err = file.WriteString(tc.fileContent)
			assert.NoError(t, err)
			file.Close()

			provider := &defaultCachedRecordProvider{file: file.Name()}
			record, err := provider.Retrieve()
			if tc.expectErrorMsg != "" {
				assert.Error(t, err)
				assert.Contains(t, err.Error(), tc.expectErrorMsg)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, record)
			}
		})
	}

	record := azidentity.AuthenticationRecord{
		TenantID:      "test-tenant-id",
		ClientID:      "test-client-id",
		Authority:     "https://login.microsoftonline.com/",
		HomeAccountID: "test-home-account-id",
		Username:      "test-username",
		Version:       "1.0",
	}

	file, err := os.CreateTemp("", "test-record-*.json")
	assert.NoError(t, err)
	defer os.Remove(file.Name())

	provider := &defaultCachedRecordProvider{file: file.Name()}
	err = provider.Store(record)
	assert.NoError(t, err)

	storedRecord, err := provider.Retrieve()
	assert.NoError(t, err)
	assert.Equal(t, record, storedRecord)
}

func TestDefaultCachedRecordProvider_NonExistentDirectory(t *testing.T) {
	tempDir, err := os.MkdirTemp("", "test-record-*")
	assert.NoError(t, err)
	defer os.RemoveAll(tempDir)

	nonExistentDir := filepath.Join(tempDir, "subdir", "nested")
	filePath := filepath.Join(nonExistentDir, "record.json")

	record := azidentity.AuthenticationRecord{
		TenantID:      "test-tenant-id",
		ClientID:      "test-client-id",
		Authority:     "https://login.microsoftonline.com/",
		HomeAccountID: "test-home-account-id",
		Username:      "test-username",
		Version:       "1.0",
	}

	provider := &defaultCachedRecordProvider{file: filePath}
	err = provider.Store(record)
	assert.NoError(t, err)

	// Verify the file was created and can be read
	storedRecord, err := provider.Retrieve()
	assert.NoError(t, err)
	assert.Equal(t, record, storedRecord)

	// Verify the directory was created with correct permissions
	fileInfo, err := os.Stat(nonExistentDir)
	assert.NoError(t, err)
	assert.True(t, fileInfo.IsDir())
}
07070100000079000081A4000000000000000000000001687816E50000049F000000000000000000000000000000000000003A00000000kubelogin-0.2.10/pkg/internal/token/azureclicredential.gopackage token

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)

type AzureCLICredential struct {
	cred *azidentity.AzureCLICredential
}

var _ CredentialProvider = (*AzureCLICredential)(nil)

func newAzureCLICredential(opts *Options) (CredentialProvider, error) {
	cred, err := azidentity.NewAzureCLICredential(&azidentity.AzureCLICredentialOptions{
		TenantID: opts.TenantID,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to create azure cli credential: %w", err)
	}
	return &AzureCLICredential{cred: cred}, nil
}

func (c *AzureCLICredential) Name() string {
	return "AzureCLICredential"
}

func (c *AzureCLICredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *AzureCLICredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	return c.cred.GetToken(ctx, opts)
}

func (c *AzureCLICredential) NeedAuthenticate() bool {
	return false
}
0707010000007A000081A4000000000000000000000001687816E5000002FB000000000000000000000000000000000000003F00000000kubelogin-0.2.10/pkg/internal/token/azureclicredential_test.gopackage token

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewAzureCLICredential(t *testing.T) {
	testCases := []struct {
		name           string
		opts           *Options
		expectErrorMsg string
		expectName     string
	}{
		{
			name: "valid options",
			opts: &Options{
				TenantID: "test-tenant-id",
			},
			expectName: "AzureCLICredential",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			cred, err := newAzureCLICredential(tc.opts)
			if tc.expectErrorMsg != "" {
				assert.Error(t, err)
				assert.Equal(t, tc.expectErrorMsg, err.Error())
				assert.Nil(t, cred)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, cred)
				assert.Equal(t, tc.expectName, cred.Name())
			}
		})
	}
}
0707010000007B000081A4000000000000000000000001687816E500000515000000000000000000000000000000000000003D00000000kubelogin-0.2.10/pkg/internal/token/azuredevopscredential.gopackage token

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)

type AzureDeveloperCLICredential struct {
	cred *azidentity.AzureDeveloperCLICredential
}

var _ CredentialProvider = (*AzureDeveloperCLICredential)(nil)

func newAzureDeveloperCLICredential(opts *Options) (CredentialProvider, error) {
	cred, err := azidentity.NewAzureDeveloperCLICredential(&azidentity.AzureDeveloperCLICredentialOptions{
		TenantID: opts.TenantID,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to create azure developer cli credential: %w", err)
	}
	return &AzureDeveloperCLICredential{cred: cred}, nil
}

func (c *AzureDeveloperCLICredential) Name() string {
	return "AzureDeveloperCLICredential"
}

func (c *AzureDeveloperCLICredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *AzureDeveloperCLICredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	return c.cred.GetToken(ctx, opts)
}

func (c *AzureDeveloperCLICredential) NeedAuthenticate() bool {
	return false
}
0707010000007C000081A4000000000000000000000001687816E500000316000000000000000000000000000000000000004200000000kubelogin-0.2.10/pkg/internal/token/azuredevopscredential_test.gopackage token

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewAzureDeveloperCLICredential(t *testing.T) {
	testCases := []struct {
		name           string
		opts           *Options
		expectErrorMsg string
		expectName     string
	}{
		{
			name: "valid options",
			opts: &Options{
				TenantID: "test-tenant-id",
			},
			expectName: "AzureDeveloperCLICredential",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			cred, err := newAzureDeveloperCLICredential(tc.opts)
			if tc.expectErrorMsg != "" {
				assert.Error(t, err)
				assert.Equal(t, tc.expectErrorMsg, err.Error())
				assert.Nil(t, cred)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, cred)
				assert.Equal(t, tc.expectName, cred.Name())
			}
		})
	}
}
0707010000007D000081A4000000000000000000000001687816E50000158B000000000000000000000000000000000000003C00000000kubelogin-0.2.10/pkg/internal/token/clientcertcredential.gopackage token

import (
	"context"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"os"
	"strings"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache"
	"golang.org/x/crypto/pkcs12"
	"k8s.io/klog/v2"
)

type ClientCertificateCredential struct {
	cred *azidentity.ClientCertificateCredential
}

var _ CredentialProvider = (*ClientCertificateCredential)(nil)

func newClientCertificateCredential(opts *Options) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	if opts.ClientCert == "" {
		return nil, fmt.Errorf("client certificate cannot be empty")
	}
	var (
		c   azidentity.Cache
		err error
	)
	if opts.UsePersistentCache {
		c, err = cache.New(nil)
		if err != nil {
			klog.V(5).Infof("failed to create cache: %v", err)
		}
	}

	// Get the certificate and private key from file
	cert, rsaPrivateKey, err := readCertificate(opts.ClientCert, opts.ClientCertPassword)
	if err != nil {
		return nil, fmt.Errorf("failed to read certificate: %w", err)
	}

	azOpts := &azidentity.ClientCertificateCredentialOptions{
		ClientOptions:            azcore.ClientOptions{Cloud: opts.GetCloudConfiguration()},
		Cache:                    c,
		SendCertificateChain:     true,
		DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
	}

	if opts.httpClient != nil {
		azOpts.ClientOptions.Transport = opts.httpClient
	}

	cred, err := azidentity.NewClientCertificateCredential(
		opts.TenantID, opts.ClientID,
		[]*x509.Certificate{cert}, rsaPrivateKey,
		azOpts)
	if err != nil {
		return nil, fmt.Errorf("failed to create client certificate credential: %w", err)
	}
	return &ClientCertificateCredential{cred: cred}, nil
}

func (c *ClientCertificateCredential) Name() string {
	return "ClientCertificateCredential"
}

func (c *ClientCertificateCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *ClientCertificateCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	return c.cred.GetToken(ctx, opts)
}

func (c *ClientCertificateCredential) NeedAuthenticate() bool {
	return false
}

func isPublicKeyEqual(key1, key2 *rsa.PublicKey) bool {
	if key1.N == nil || key2.N == nil {
		return false
	}
	return key1.E == key2.E && key1.N.Cmp(key2.N) == 0
}

func splitPEMBlock(pemBlock []byte) (certPEM []byte, keyPEM []byte) {
	for {
		var derBlock *pem.Block
		derBlock, pemBlock = pem.Decode(pemBlock)
		if derBlock == nil {
			break
		}
		if derBlock.Type == "CERTIFICATE" {
			certPEM = append(certPEM, pem.EncodeToMemory(derBlock)...)
		} else if derBlock.Type == "PRIVATE KEY" {
			keyPEM = append(keyPEM, pem.EncodeToMemory(derBlock)...)
		}
	}

	return certPEM, keyPEM
}

func parseRsaPrivateKey(privateKeyPEM []byte) (*rsa.PrivateKey, error) {
	block, _ := pem.Decode(privateKeyPEM)
	if block == nil {
		return nil, fmt.Errorf("failed to decode a pem block from private key")
	}

	privatePkcs1Key, errPkcs1 := x509.ParsePKCS1PrivateKey(block.Bytes)
	if errPkcs1 == nil {
		return privatePkcs1Key, nil
	}

	privatePkcs8Key, errPkcs8 := x509.ParsePKCS8PrivateKey(block.Bytes)
	if errPkcs8 == nil {
		privatePkcs8RsaKey, ok := privatePkcs8Key.(*rsa.PrivateKey)
		if !ok {
			return nil, fmt.Errorf("pkcs8 contained non-RSA key. Expected RSA key")
		}
		return privatePkcs8RsaKey, nil
	}

	return nil, fmt.Errorf("failed to parse private key as Pkcs#1 or Pkcs#8. (%w), (%w)", errPkcs1, errPkcs8)
}

func parseKeyPairFromPEMBlock(pemBlock []byte) (*x509.Certificate, *rsa.PrivateKey, error) {
	certPEM, keyPEM := splitPEMBlock(pemBlock)

	privateKey, err := parseRsaPrivateKey(keyPEM)
	if err != nil {
		return nil, nil, err
	}

	found := false
	var cert *x509.Certificate
	for {
		var certBlock *pem.Block
		var err error
		certBlock, certPEM = pem.Decode(certPEM)
		if certBlock == nil {
			break
		}

		cert, err = x509.ParseCertificate(certBlock.Bytes)
		if err != nil {
			return nil, nil, fmt.Errorf("unable to parse certificate: %w", err)
		}

		certPublicKey, ok := cert.PublicKey.(*rsa.PublicKey)
		if ok && isPublicKeyEqual(certPublicKey, &privateKey.PublicKey) {
			found = true
			break
		}
	}

	if !found {
		return nil, nil, fmt.Errorf("unable to find a matching public certificate")
	}

	return cert, privateKey, nil
}

func decodePkcs12(pkcs []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
	blocks, err := pkcs12.ToPEM(pkcs, password)
	if err != nil {
		return nil, nil, err
	}

	var pemData []byte
	for _, b := range blocks {
		pemData = append(pemData, pem.EncodeToMemory(b)...)
	}

	return parseKeyPairFromPEMBlock(pemData)
}

func readCertificate(certFile, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
	if strings.HasSuffix(certFile, ".pfx") {
		cert, err := os.ReadFile(certFile)
		if err != nil {
			return nil, nil, fmt.Errorf("failed to read the certificate file (%s): %w", certFile, err)
		}
		return decodePkcs12(cert, password)
	} else {
		cert, err := os.ReadFile(certFile)
		if err != nil {
			return nil, nil, fmt.Errorf("failed to read the certificate file (%s): %w", certFile, err)
		}
		return parseKeyPairFromPEMBlock(cert)
	}
}
0707010000007E000081A4000000000000000000000001687816E500000447000000000000000000000000000000000000004100000000kubelogin-0.2.10/pkg/internal/token/clientcertcredential_test.gopackage token

import (
	"context"
	"os"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/kubelogin/pkg/internal/testutils"
	"github.com/stretchr/testify/assert"
)

func TestClientCertCredential_GetToken(t *testing.T) {
	certFile := os.Getenv("KUBELOGIN_LIVETEST_CERTIFICATE_FILE")
	if certFile == "" {
		certFile = "fixtures/cert.pem"
	}

	rec, err := testutils.GetVCRHttpClient("fixtures/client_cert_credential", testutils.TestTenantID)
	if err != nil {
		t.Fatalf("failed to create recorder: %v", err)
	}
	defer rec.Stop()

	opts := &Options{
		ClientID:   testutils.TestClientID,
		ServerID:   testutils.TestServerID,
		ClientCert: certFile,
		TenantID:   testutils.TestTenantID,
		httpClient: rec.GetDefaultClient(),
	}

	cred, err := newClientCertificateCredential(opts)
	if err != nil {
		t.Fatalf("failed to create credential: %v", err)
	}

	token, err := cred.GetToken(context.Background(), policy.TokenRequestOptions{
		Scopes: []string{opts.ServerID + "/.default"},
	})
	assert.NoError(t, err)
	assert.Equal(t, testutils.TestToken, token.Token)
}
0707010000007F000081A4000000000000000000000001687816E500000C97000000000000000000000000000000000000004300000000kubelogin-0.2.10/pkg/internal/token/clientcertcredentialwithpop.gopackage token

import (
	"context"
	"crypto/x509"
	"fmt"
	"time"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/kubelogin/pkg/internal/pop"
	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
)

type ClientCertificateCredentialWithPoP struct {
	popClaims map[string]string
	cred      confidential.Credential
	client    confidential.Client
	options   *pop.MsalClientOptions
}

var _ CredentialProvider = (*ClientCertificateCredentialWithPoP)(nil)

func newClientCertificateCredentialWithPoP(opts *Options) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	if opts.ClientCert == "" {
		return nil, fmt.Errorf("client certificate cannot be empty")
	}
	popClaimsMap, err := parsePoPClaims(opts.PoPTokenClaims)
	if err != nil {
		return nil, fmt.Errorf("unable to parse PoP claims: %w", err)
	}
	if len(popClaimsMap) == 0 {
		return nil, fmt.Errorf("number of pop claims is invalid: %d", len(popClaimsMap))
	}

	// Get the certificate and private key from cert file
	cert, rsaPrivateKey, err := readCertificate(opts.ClientCert, opts.ClientCertPassword)
	if err != nil {
		return nil, fmt.Errorf("failed to read certificate: %w", err)
	}

	cred, err := confidential.NewCredFromCert([]*x509.Certificate{cert}, rsaPrivateKey)
	if err != nil {
		return nil, fmt.Errorf("unable to create credential from certificate: %w", err)
	}
	msalOpts := &pop.MsalClientOptions{
		Authority:                opts.GetCloudConfiguration().ActiveDirectoryAuthorityHost,
		ClientID:                 opts.ClientID,
		TenantID:                 opts.TenantID,
		DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
	}
	if opts.httpClient != nil {
		msalOpts.Options.Transport = opts.httpClient
	}
	client, err := pop.NewConfidentialClient(cred, msalOpts)
	if err != nil {
		return nil, fmt.Errorf("unable to create confidential client: %w", err)
	}

	return &ClientCertificateCredentialWithPoP{
		popClaims: popClaimsMap,
		cred:      cred,
		client:    client,
		options:   msalOpts,
	}, nil
}

func (c *ClientCertificateCredentialWithPoP) Name() string {
	return "ClientCertificateCredentialWithPoP"
}

func (c *ClientCertificateCredentialWithPoP) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *ClientCertificateCredentialWithPoP) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	accessToken, expiresOn, err := pop.AcquirePoPTokenConfidential(
		ctx,
		c.popClaims,
		opts.Scopes,
		c.client,
		c.options.TenantID,
		pop.GetSwPoPKey,
	)
	if err != nil {
		return azcore.AccessToken{}, fmt.Errorf("failed to create PoP token using client certificate credential: %w", err)
	}
	return azcore.AccessToken{Token: accessToken, ExpiresOn: time.Unix(expiresOn, 0)}, nil
}

func (c *ClientCertificateCredentialWithPoP) NeedAuthenticate() bool {
	return false
}
07070100000080000081A4000000000000000000000001687816E500000D72000000000000000000000000000000000000004800000000kubelogin-0.2.10/pkg/internal/token/clientcertcredentialwithpop_test.gopackage token

import (
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewClientCertificateCredentialWithPoP(t *testing.T) {
	certFile := os.Getenv("KUBELOGIN_LIVETEST_CERTIFICATE_FILE")
	if certFile == "" {
		certFile = "fixtures/cert.pem"
	}

	testCases := []struct {
		name           string
		opts           *Options
		expectErrorMsg string
		expectName     string
	}{
		{
			name: "valid options",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				ClientCert:        certFile,
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectName: "ClientCertificateCredentialWithPoP",
		},
		{
			name: "missing client ID",
			opts: &Options{
				TenantID:          "test-tenant-id",
				ClientCert:        certFile,
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectErrorMsg: "client ID cannot be empty",
		},
		{
			name: "missing tenant ID",
			opts: &Options{
				ClientID:          "test-client-id",
				ClientCert:        certFile,
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectErrorMsg: "tenant ID cannot be empty",
		},
		{
			name: "missing client certificate",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectErrorMsg: "client certificate cannot be empty",
		},
		{
			name: "missing PoP claims",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				ClientCert:        certFile,
				IsPoPTokenEnabled: true,
			},
			expectErrorMsg: "unable to parse PoP claims: failed to parse PoP token claims: no claims provided",
		},
		{
			name: "invalid PoP claims format",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				ClientCert:        certFile,
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "invalid-format",
			},
			expectErrorMsg: "unable to parse PoP claims: failed to parse PoP token claims. Ensure the claims are formatted as `key=value` with no extra whitespace",
		},
		{
			name: "missing required u-claim",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				ClientCert:        certFile,
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "key=value",
			},
			expectErrorMsg: "unable to parse PoP claims: required u-claim not provided for PoP token flow. Please provide the ARM ID of the cluster in the format `u=<ARM_ID>`",
		},
		{
			name: "invalid certificate file",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				ClientCert:        "nonexistent.pem",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectErrorMsg: "failed to read certificate: failed to read the certificate file (nonexistent.pem):",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			cred, err := newClientCertificateCredentialWithPoP(tc.opts)

			if tc.expectErrorMsg != "" {
				assert.Error(t, err)
				if tc.expectErrorMsg != "" {
					assert.Contains(t, err.Error(), tc.expectErrorMsg)
				}
				assert.Nil(t, cred)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, cred)
				assert.Equal(t, tc.expectName, cred.Name())
			}
		})
	}
}
07070100000081000081A4000000000000000000000001687816E500000806000000000000000000000000000000000000003E00000000kubelogin-0.2.10/pkg/internal/token/clientsecretcredential.gopackage token

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache"
	"k8s.io/klog/v2"
)

type ClientSecretCredential struct {
	cred *azidentity.ClientSecretCredential
}

var _ CredentialProvider = (*ClientSecretCredential)(nil)

func newClientSecretCredential(opts *Options) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	if opts.ClientSecret == "" {
		return nil, fmt.Errorf("client secret cannot be empty")
	}
	var (
		c   azidentity.Cache
		err error
	)
	if opts.UsePersistentCache {
		c, err = cache.New(nil)
		if err != nil {
			klog.V(5).Infof("failed to create cache: %v", err)
		}
	}

	azOpts := &azidentity.ClientSecretCredentialOptions{
		ClientOptions:            azcore.ClientOptions{Cloud: opts.GetCloudConfiguration()},
		Cache:                    c,
		DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
	}

	if opts.httpClient != nil {
		azOpts.ClientOptions.Transport = opts.httpClient
	}

	cred, err := azidentity.NewClientSecretCredential(
		opts.TenantID, opts.ClientID, opts.ClientSecret, azOpts)
	if err != nil {
		return nil, fmt.Errorf("failed to create client secret credential: %w", err)
	}
	return &ClientSecretCredential{cred: cred}, nil
}

func (c *ClientSecretCredential) Name() string {
	return "ClientSecretCredential"
}

func (c *ClientSecretCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *ClientSecretCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	return c.cred.GetToken(ctx, opts)
}

func (c *ClientSecretCredential) NeedAuthenticate() bool {
	return false
}
07070100000082000081A4000000000000000000000001687816E5000003D4000000000000000000000000000000000000004300000000kubelogin-0.2.10/pkg/internal/token/clientsecretcredential_test.gopackage token

import (
	"context"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/kubelogin/pkg/internal/testutils"
	"github.com/stretchr/testify/assert"
)

func TestClientSecretCredential_GetToken(t *testing.T) {
	rec, err := testutils.GetVCRHttpClient("fixtures/client_secret_credential", testutils.TestTenantID)
	if err != nil {
		t.Fatalf("failed to create recorder: %v", err)
	}
	defer rec.Stop()

	opts := &Options{
		ClientID:     testutils.TestClientID,
		ServerID:     testutils.TestServerID,
		ClientSecret: "password",
		TenantID:     testutils.TestTenantID,
		httpClient:   rec.GetDefaultClient(),
	}

	cred, err := newClientSecretCredential(opts)
	if err != nil {
		t.Fatalf("failed to create credential: %v", err)
	}

	token, err := cred.GetToken(context.Background(), policy.TokenRequestOptions{
		Scopes: []string{opts.ServerID + "/.default"},
	})
	assert.NoError(t, err)
	assert.Equal(t, testutils.TestToken, token.Token)
}
07070100000083000081A4000000000000000000000001687816E500000B57000000000000000000000000000000000000004500000000kubelogin-0.2.10/pkg/internal/token/clientsecretcredentialwithpop.gopackage token

import (
	"context"
	"fmt"
	"time"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/kubelogin/pkg/internal/pop"
	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
)

type ClientSecretCredentialWithPoP struct {
	popClaims map[string]string
	cred      confidential.Credential
	client    confidential.Client
	options   *pop.MsalClientOptions
}

var _ CredentialProvider = (*ClientSecretCredentialWithPoP)(nil)

func newClientSecretCredentialWithPoP(opts *Options) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	if opts.ClientSecret == "" {
		return nil, fmt.Errorf("client secret cannot be empty")
	}
	popClaimsMap, err := parsePoPClaims(opts.PoPTokenClaims)
	if err != nil {
		return nil, fmt.Errorf("unable to parse PoP claims: %w", err)
	}
	if len(popClaimsMap) == 0 {
		return nil, fmt.Errorf("number of pop claims is invalid: %d", len(popClaimsMap))
	}

	cred, err := confidential.NewCredFromSecret(opts.ClientSecret)
	if err != nil {
		return nil, fmt.Errorf("unable to create confidential credential: %w", err)
	}
	msalOpts := &pop.MsalClientOptions{
		Authority:                opts.GetCloudConfiguration().ActiveDirectoryAuthorityHost,
		ClientID:                 opts.ClientID,
		TenantID:                 opts.TenantID,
		DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
	}
	if opts.httpClient != nil {
		msalOpts.Options.Transport = opts.httpClient
	}
	client, err := pop.NewConfidentialClient(cred, msalOpts)
	if err != nil {
		return nil, fmt.Errorf("unable to create confidential client: %w", err)
	}

	return &ClientSecretCredentialWithPoP{
		popClaims: popClaimsMap,
		cred:      cred,
		client:    client,
		options:   msalOpts,
	}, nil
}

func (c *ClientSecretCredentialWithPoP) Name() string {
	return "ClientSecretCredentialWithPoP"
}

func (c *ClientSecretCredentialWithPoP) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *ClientSecretCredentialWithPoP) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	accessToken, expiresOn, err := pop.AcquirePoPTokenConfidential(
		ctx,
		c.popClaims,
		opts.Scopes,
		c.client,
		c.options.TenantID,
		pop.GetSwPoPKey,
	)
	if err != nil {
		return azcore.AccessToken{}, fmt.Errorf("failed to create PoP token using client secret credential: %w", err)
	}
	return azcore.AccessToken{Token: accessToken, ExpiresOn: time.Unix(expiresOn, 0)}, nil
}

func (c *ClientSecretCredentialWithPoP) NeedAuthenticate() bool {
	return false
}
07070100000084000081A4000000000000000000000001687816E500000B5B000000000000000000000000000000000000004A00000000kubelogin-0.2.10/pkg/internal/token/clientsecretcredentialwithpop_test.gopackage token

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewClientSecretCredentialWithPoP(t *testing.T) {
	testCases := []struct {
		name           string
		opts           *Options
		expectErrorMsg string
		expectName     string
	}{
		{
			name: "valid options",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				ClientSecret:      "test-secret",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectName: "ClientSecretCredentialWithPoP",
		},
		{
			name: "missing client ID",
			opts: &Options{
				TenantID:          "test-tenant-id",
				ClientSecret:      "test-secret",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectErrorMsg: "client ID cannot be empty",
		},
		{
			name: "missing tenant ID",
			opts: &Options{
				ClientID:          "test-client-id",
				ClientSecret:      "test-secret",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectErrorMsg: "tenant ID cannot be empty",
		},
		{
			name: "missing client secret",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectErrorMsg: "client secret cannot be empty",
		},
		{
			name: "missing PoP claims",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				ClientSecret:      "test-secret",
				IsPoPTokenEnabled: true,
			},
			expectErrorMsg: "unable to parse PoP claims: failed to parse PoP token claims: no claims provided",
		},
		{
			name: "invalid PoP claims format",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				ClientSecret:      "test-secret",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "invalid-format",
			},
			expectErrorMsg: "unable to parse PoP claims: failed to parse PoP token claims. Ensure the claims are formatted as `key=value` with no extra whitespace",
		},
		{
			name: "missing required u-claim",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				ClientSecret:      "test-secret",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "key=value",
			},
			expectErrorMsg: "unable to parse PoP claims: required u-claim not provided for PoP token flow. Please provide the ARM ID of the cluster in the format `u=<ARM_ID>`",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			cred, err := newClientSecretCredentialWithPoP(tc.opts)
			if tc.expectErrorMsg != "" {
				assert.Error(t, err)
				assert.Equal(t, tc.expectErrorMsg, err.Error())
				assert.Nil(t, cred)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, cred)
				assert.Equal(t, tc.expectName, cred.Name())
			}
		})
	}
}
07070100000085000081A4000000000000000000000001687816E50000087B000000000000000000000000000000000000003C00000000kubelogin-0.2.10/pkg/internal/token/devicecodecredential.gopackage token

import (
	"context"
	"fmt"
	"os"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache"
	"k8s.io/klog/v2"
)

type DeviceCodeCredential struct {
	cred *azidentity.DeviceCodeCredential
}

var _ CredentialProvider = (*DeviceCodeCredential)(nil)

func newDeviceCodeCredential(opts *Options, record azidentity.AuthenticationRecord) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	var (
		c   azidentity.Cache
		err error
	)
	if opts.UsePersistentCache {
		c, err = cache.New(nil)
		if err != nil {
			klog.V(5).Infof("failed to create cache: %v", err)
		}
	}

	azOpts := &azidentity.DeviceCodeCredentialOptions{
		ClientOptions:            azcore.ClientOptions{Cloud: opts.GetCloudConfiguration()},
		AuthenticationRecord:     record,
		Cache:                    c,
		ClientID:                 opts.ClientID,
		TenantID:                 opts.TenantID,
		DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
		UserPrompt: func(ctx context.Context, dcm azidentity.DeviceCodeMessage) error {
			_, err := fmt.Fprintln(os.Stderr, dcm.Message)
			return err
		},
	}

	if opts.httpClient != nil {
		azOpts.ClientOptions.Transport = opts.httpClient
	}

	cred, err := azidentity.NewDeviceCodeCredential(azOpts)
	if err != nil {
		return nil, fmt.Errorf("failed to create device code credential: %w", err)
	}
	return &DeviceCodeCredential{cred: cred}, nil
}

func (c *DeviceCodeCredential) Name() string {
	return "DeviceCodeCredential"
}

func (c *DeviceCodeCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return c.cred.Authenticate(ctx, opts)
}

func (c *DeviceCodeCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	return c.cred.GetToken(ctx, opts)
}

func (c *DeviceCodeCredential) NeedAuthenticate() bool {
	return true
}
07070100000086000081A4000000000000000000000001687816E500000413000000000000000000000000000000000000004100000000kubelogin-0.2.10/pkg/internal/token/devicecodecredential_test.gopackage token

import (
	"context"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/kubelogin/pkg/internal/testutils"
	"github.com/stretchr/testify/assert"
)

func TestDeviceCodeCredential_GetToken(t *testing.T) {
	rec, err := testutils.GetVCRHttpClient("fixtures/device_code_credential", testutils.TestTenantID)
	if err != nil {
		t.Fatalf("failed to create recorder: %v", err)
	}
	defer rec.Stop()

	opts := &Options{
		ClientID:   testutils.TestClientID,
		ServerID:   testutils.TestServerID,
		TenantID:   testutils.TestTenantID,
		httpClient: rec.GetDefaultClient(),
	}

	record := azidentity.AuthenticationRecord{}
	cred, err := newDeviceCodeCredential(opts, record)
	if err != nil {
		t.Fatalf("failed to create credential: %v", err)
	}

	token, err := cred.GetToken(context.Background(), policy.TokenRequestOptions{
		Scopes: []string{opts.ServerID + "/.default"},
	})
	assert.NoError(t, err)
	assert.Equal(t, testutils.TestToken, token.Token)
}
07070100000087000081A4000000000000000000000001687816E500000A8D000000000000000000000000000000000000003C00000000kubelogin-0.2.10/pkg/internal/token/execCredentialPlugin.gopackage token

//go:generate sh -c "mockgen -destination mock_$GOPACKAGE/execCredentialPlugin.go github.com/Azure/kubelogin/pkg/internal/token ExecCredentialPlugin"

import (
	"context"
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	klog "k8s.io/klog/v2"
)

type ExecCredentialPlugin interface {
	Do(ctx context.Context) error
}

type execCredentialPlugin struct {
	o                    *Options
	cachedRecord         CachedRecordProvider
	execCredentialWriter ExecCredentialWriter
	newCredentialFunc    func(record azidentity.AuthenticationRecord, o *Options) (CredentialProvider, error)
}

var errAuthenticateNotSupported = errors.New("authenticate is not supported")

func New(o *Options) (ExecCredentialPlugin, error) {
	klog.V(10).Info(o.ToString())
	return &execCredentialPlugin{
		o:                    o,
		execCredentialWriter: &execCredentialWriter{},
		cachedRecord: &defaultCachedRecordProvider{
			file: o.authRecordCacheFile,
		},
		newCredentialFunc: NewAzIdentityCredential,
	}, nil
}

func (p *execCredentialPlugin) Do(ctx context.Context) error {
	if p.o.ServerID == "" {
		return errors.New("server-id is required")
	}

	ctx, cancel := context.WithTimeout(ctx, p.o.Timeout)
	defer cancel()

	record, err := p.cachedRecord.Retrieve()
	if err != nil {
		klog.V(5).Infof("failed to retrieve cached record: %s", err)
	}

	cred, err := p.newCredentialFunc(record, p.o)
	if err != nil {
		return fmt.Errorf("failed to create azidentity credential: %w", err)
	}

	klog.V(5).Infof("using credential: %s", cred.Name())
	scopes := []string{GetScope(p.o.ServerID)}
	tokenRequestOptions := policy.TokenRequestOptions{
		TenantID: p.o.TenantID,
		Scopes:   scopes,
	}

	if cred.NeedAuthenticate() && record == (azidentity.AuthenticationRecord{}) {
		// No stored record; call Authenticate to acquire one.
		// This will prompt the user to authenticate interactively.
		klog.V(5).Info("no stored record; calling Authenticate")
		record, err = cred.Authenticate(ctx, &tokenRequestOptions)
		if err != nil {
			return fmt.Errorf("failed to authenticate: %w", err)
		}
		err = p.cachedRecord.Store(record)
		if err != nil {
			return fmt.Errorf("failed to store record: %w", err)
		}
	}
	klog.V(5).Infof("getting token with scopes: %v", scopes)
	token, err := cred.GetToken(ctx, tokenRequestOptions)
	if err != nil {
		return fmt.Errorf("failed to get token: %w", err)
	}

	return p.execCredentialWriter.Write(token, os.Stdout)
}

func GetScope(serverID string) string {
	scope := strings.TrimRight(serverID, "/")
	if !strings.HasSuffix(scope, defaultScope) {
		scope += defaultScope
	}
	return scope
}
07070100000088000081A4000000000000000000000001687816E50000034C000000000000000000000000000000000000004100000000kubelogin-0.2.10/pkg/internal/token/execCredentialPlugin_test.gopackage token

import (
	"os"
	"testing"
)

func TestKUBERNETES_EXEC_INFOIsEmpty(t *testing.T) {
	testData := []struct {
		name            string
		execInfoEnvTest string
		options         Options
	}{
		{
			name:            "KUBERNETES_EXEC_INFO is empty",
			execInfoEnvTest: "",
			options: Options{
				LoginMethod: DeviceCodeLogin,
				ClientID:    "clientID",
				ServerID:    "serverID",
				TenantID:    "tenantID",
			},
		},
	}

	for _, data := range testData {
		t.Run(data.name, func(t *testing.T) {
			os.Setenv("KUBERNETES_EXEC_INFO", data.execInfoEnvTest)
			defer os.Unsetenv("KUBERNETES_EXEC_INFO")
			ecp, err := New(&data.options)
			if ecp == nil || err != nil {
				t.Fatalf("expected: return execCredentialPlugin and nil error, actual: did not return execCredentialPlugin or did not return expected error")
			}
		})
	}
}
07070100000089000081A4000000000000000000000001687816E5000009D2000000000000000000000000000000000000003C00000000kubelogin-0.2.10/pkg/internal/token/execCredentialWriter.gopackage token

//go:generate sh -c "mockgen -destination mock_$GOPACKAGE/execCredentialWriter.go github.com/Azure/kubelogin/pkg/internal/token ExecCredentialWriter"

import (
	"encoding/json"
	"fmt"
	"io"
	"os"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/pkg/apis/clientauthentication"
	v1 "k8s.io/client-go/pkg/apis/clientauthentication/v1"
	"k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
)

const (
	apiV1       string = "client.authentication.k8s.io/v1"
	apiV1beta1  string = "client.authentication.k8s.io/v1beta1"
	execInfoEnv string = "KUBERNETES_EXEC_INFO"
)

type ExecCredentialWriter interface {
	Write(token azcore.AccessToken, writer io.Writer) error
}

type execCredentialWriter struct{}

// Write writes the ExecCredential to standard output for kubectl.
func (*execCredentialWriter) Write(accessToken azcore.AccessToken, writer io.Writer) error {
	apiVersionFromEnv, err := getAPIVersionFromExecInfoEnv()
	if err != nil {
		return err
	}
	// Support both apiVersions of client.authentication.k8s.io/v1beta1 and client.authentication.k8s.io/v1
	var ec interface{}
	t := metav1.NewTime(accessToken.ExpiresOn)
	switch apiVersionFromEnv {
	case apiV1beta1:
		ec = &v1beta1.ExecCredential{
			TypeMeta: metav1.TypeMeta{
				APIVersion: apiV1beta1,
				Kind:       "ExecCredential",
			},
			Status: &v1beta1.ExecCredentialStatus{
				Token:               accessToken.Token,
				ExpirationTimestamp: &t,
			},
		}
	case apiV1:
		ec = &v1.ExecCredential{
			TypeMeta: metav1.TypeMeta{
				APIVersion: apiV1,
				Kind:       "ExecCredential",
			},
			Status: &v1.ExecCredentialStatus{
				Token:               accessToken.Token,
				ExpirationTimestamp: &t,
			},
		}
	}

	e := json.NewEncoder(writer)
	if err := e.Encode(ec); err != nil {
		return fmt.Errorf("could not write the ExecCredential: %w", err)
	}
	return nil
}

func getAPIVersionFromExecInfoEnv() (string, error) {
	env := os.Getenv(execInfoEnv)
	if env == "" {
		return apiV1beta1, nil
	}
	var execCredential clientauthentication.ExecCredential
	if err := json.Unmarshal([]byte(env), &execCredential); err != nil {
		return "", fmt.Errorf("cannot unmarshal %q to ExecCredential: %w", env, err)
	}
	switch execCredential.TypeMeta.APIVersion {
	case "":
		return apiV1beta1, nil
	case apiV1, apiV1beta1:
		return execCredential.TypeMeta.APIVersion, nil
	default:
		return "", fmt.Errorf("api version: %s is not supported", execCredential.TypeMeta.APIVersion)
	}
}
0707010000008A000081A4000000000000000000000001687816E5000008BE000000000000000000000000000000000000004100000000kubelogin-0.2.10/pkg/internal/token/execCredentialWriter_test.gopackage token

import (
	"bytes"
	"encoding/json"
	"os"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"k8s.io/client-go/pkg/apis/clientauthentication"
)

func TestExecCredentialWriterAPIVersion(t *testing.T) {
	testData := []struct {
		name               string
		execInfoEnvTest    string
		expectedAPIVersion string
	}{
		{
			name:               "KUBERNETES_EXEC_INFO is empty",
			execInfoEnvTest:    "",
			expectedAPIVersion: "client.authentication.k8s.io/v1beta1",
		},
		{
			name:               "KUBERNETES_EXEC_INFO is present and apiVersion is absent",
			execInfoEnvTest:    `{"kind":"ExecCredential","spec":{"interactive":true},"apiVersion":""}`,
			expectedAPIVersion: "client.authentication.k8s.io/v1beta1",
		},
		{
			name:               "KUBERNETES_EXEC_INFO is present and apiVersion is neither v1 or v1beta1",
			execInfoEnvTest:    `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1alpha1","spec":{"interactive":true}}`,
			expectedAPIVersion: "",
		},
		{
			name:               "KUBERNETES_EXEC_INFO is present and apiVersion is v1beta1",
			execInfoEnvTest:    `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1beta1","spec":{"interactive":true}}`,
			expectedAPIVersion: "client.authentication.k8s.io/v1beta1",
		},
		{
			name:               "KUBERNETES_EXEC_INFO is present and apiVersion is v1",
			execInfoEnvTest:    `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1","spec":{"interactive":true}}`,
			expectedAPIVersion: "client.authentication.k8s.io/v1",
		},
	}

	for _, data := range testData {
		t.Run(data.name, func(t *testing.T) {
			os.Setenv("KUBERNETES_EXEC_INFO", data.execInfoEnvTest)
			defer os.Unsetenv("KUBERNETES_EXEC_INFO")
			ecw := execCredentialWriter{}
			stringBufferTest := new(bytes.Buffer)
			azToken := azcore.AccessToken{
				Token: "access-token",
			}
			ecw.Write(azToken, stringBufferTest)
			var execCredential clientauthentication.ExecCredential
			json.Unmarshal(stringBufferTest.Bytes(), &execCredential)
			if execCredential.TypeMeta.APIVersion != data.expectedAPIVersion {
				t.Fatalf("expected: %s, actual: %s", data.expectedAPIVersion, execCredential.TypeMeta.APIVersion)
			}
		})
	}
}
0707010000008B000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002D00000000kubelogin-0.2.10/pkg/internal/token/fixtures0707010000008C000081A4000000000000000000000001687816E500000ACA000000000000000000000000000000000000003600000000kubelogin-0.2.10/pkg/internal/token/fixtures/cert.pem-----BEGIN CERTIFICATE-----
MIIC3DCCAcSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQKEwtFeGFt
cGxlIE9yZzAeFw0yNTAyMjYxNzM3MTRaFw0yNjAyMjYxNzM3MTRaMBYxFDASBgNV
BAoTC0V4YW1wbGUgT3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
41kp4aOyHwZkDd8o9Q/NRGGFSUXIdlScgLe9ZNtQWwG1r8enUZ0DDHMsTuJBuNR5
VS7E/eIXsbz7nHq7OYwdBHc9INVZ8t/WXRwVbzNe3PmGETNn6Ip+QDeOQXm+R7c6
xpH7d/ATRm5H3HhzEjpX4KbLby1y0ue4RdkWSaWbv7CIPt9g/JzrwecQ9h5q6i3t
QNoUi9ZImlTBbXhJh3/W8zi3dWCYr2JwT7883Iw5bFpkfFg+yXFq7a1tVj3gterL
rgdjgyaRvUPZSgk6lCmBYBuAdhks2Mv4T8T/b2b72+H7vKfjuR/IziPTxP0YOlSZ
DWghT3VrRB1EfvjO1wKA8QIDAQABozUwMzAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0l
BAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEA
SfXdt6O6HmlTWypTdxNisALn4lMO7RhXn3ixI08ufI6RwVqhSvWhGwKL+uR+HGww
w+uiaWgUxXmp8ocQmsoRns+Wx1pvjD2+/27si39rJuLWzAE/DViN1KYqsB7b0Su9
JmpZBruIT6lWYKfG4KmJBo15++ttAeyfnL/5eyl1Uu9s+JsPsgr6vWAH7IZV0GRC
rVstolS2nBcQOsO+nHABJFavjYQP3Wo5Ei+50im7BdlaVmA+BpV5WrGkEGTyI0Qv
Tld5IEcrZeuVb5jBM2fpbLXA8a3aGzU8eetIBbw7p8jTqeE1Y58ZW00KcJVtR3/i
xkQDJ9mGcA6z1D0/2SJlFw==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDjWSnho7IfBmQN
3yj1D81EYYVJRch2VJyAt71k21BbAbWvx6dRnQMMcyxO4kG41HlVLsT94hexvPuc
ers5jB0Edz0g1Vny39ZdHBVvM17c+YYRM2foin5AN45Beb5HtzrGkft38BNGbkfc
eHMSOlfgpstvLXLS57hF2RZJpZu/sIg+32D8nOvB5xD2HmrqLe1A2hSL1kiaVMFt
eEmHf9bzOLd1YJivYnBPvzzcjDlsWmR8WD7JcWrtrW1WPeC16suuB2ODJpG9Q9lK
CTqUKYFgG4B2GSzYy/hPxP9vZvvb4fu8p+O5H8jOI9PE/Rg6VJkNaCFPdWtEHUR+
+M7XAoDxAgMBAAECggEBAJOLNib9uYdw+lYWUdpY2vpZ38phw2soFjljBUMDIe8t
+N+PTwMkRuo5hLPdGpH9MpEZvTaXGJF8+D3hWMhMKjjPuZgpXirFIbVjmHWGfTYj
qeJX3kOIPc8nPuc3P0oDm91quCxqXdgDkhd/BA78VjOxi60nbbF6OJj7/f7lv2Jy
0YR1jq6xEcRChIvuQN/IONtwLQDGJ/okQIsbcptwlvS62QkbxDFmB4Gb67tqlw+T
HZS0McMw9357y0yQOh/xRCsrd1q3WoDEnxFi+1mnHuGmAgxBkBSRHPoq++mASw+v
Lp5zJS0sJlMsY6G/RjbS0hWPuqk1MGzcJ7EPMOg9nBECgYEA9m1EiU47bh9Mayaa
VZrrjfkN5a6Igknlf/N238ORsmraF4mAOEgJ53+Y0wMtj5ODsBUrv0/ykCxkPWKz
WfmZMgwZGsMdXaEt0kGCFPXNYhuoX01Nvek97wZORUCruCu8zuHI1D6BXLpekRy2
N7u0EbyUBzjrw1t8fJT0cKJ0Lf8CgYEA7C4olUEHd8bWNPOjHMLLGIwYTwY2xw8K
9o5TYa65YLb4SoYstrWIAb+70iyieHpsc015W5S7ran8D6nMmUXqrLK2xhnGYqXa
qDXBHhQ4lS/cAaFYccOPkV5o/c8f3+SqX7GSBQEG8GcnR+rIBVF6dX9IxdcrrW8Q
nE4hupaaMQ8CgYEAoBB/iRRYxAHueFcdvmcfhBt27G6+2qo3OTIiT9xPYe3H9avp
riUU0druoHma+Xye+Bv4S48Zho5fGgRnbRUUbg6vq9N62ptcEQtd/FFg8831QtoK
mkXLZdvZsV/9amZ2gIbmFP74tguUa3uT3IW+xBqSqFJPyZg+Nwnl8NeE0W8CgYBv
mRP2Cocz0pFu7dyZ/3UmATSPSplhj7sXa4L8uinACFTkKehA4SAF64odMpgGo5pR
FT+NxYa09Yg0AoC5v+62ca+phY5XGJVsPBInW1itLbMgVhPLlaNmBh1IKLGgApV6
qBYeJTEZMTS/Z7HhyXE6yc0iJpzt03ge01BesUDkgwKBgQDLa02L362TiegTYNN9
2CrJR9Z+OSg+Nmc4lCxGLx3KSMDAmJDVOpE+VB7znRo1K8U+qglfShtEB8WWaWMB
GsVvxMny+90qyUDAo7gZi86x908oYUy7BKv36ZjV9f2TFEsHFAWnuWyPg7arYXn2
Omaw1wxaRHrnjgZ1GB9z00x3tQ==
-----END PRIVATE KEY-----
0707010000008D000081A4000000000000000000000001687816E500002E87000000000000000000000000000000000000004900000000kubelogin-0.2.10/pkg/internal/token/fixtures/client_cert_credential.yaml---
version: 2
interactions:
    - id: 0
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 4834edb5-48f7-4a5d-9813-6cdbfa084f0c
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=https%3A%2F%2Flogin.microsoftonline.com%2F00000000-0000-0000-0000-000000000000%2Foauth2%2Fv2.0%2Fauthorize
        method: GET
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 980
        uncompressed: false
        body: '{"tenant_discovery_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 4834edb5-48f7-4a5d-9813-6cdbfa084f0c
            Content-Length:
                - "980"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-THS4Pc6YgxpG7SHDuZ5OPw' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 00:18:08 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.20106.4 - EUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 310.985686ms
    - id: 1
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - eb28ecfd-0c6d-4247-854e-70c89ee1d29b
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration
        method: GET
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 1753
        uncompressed: false
        body: '{"token_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/kerberos","tenant_region_scope":"NA","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - eb28ecfd-0c6d-4247-854e-70c89ee1d29b
            Content-Length:
                - "1753"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-cHJcUTLuBn9G7NU_FsKtvA' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 00:18:09 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.20106.4 - EUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 113.101786ms
    - id: 2
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 2541
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: client_assertion=[REDACTED]&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_id=[REDACTED]&client_info=1&grant_type=client_credentials&scope=6dae42f8-4368-4678-94ff-3960e28e3630%2F.default+openid+offline_access+profile
        form:
            client_assertion:
                - '[REDACTED]'
            client_assertion_type:
                - urn:ietf:params:oauth:client-assertion-type:jwt-bearer
            client_id:
                - '[REDACTED]'
            client_info:
                - "1"
            grant_type:
                - client_credentials
            scope:
                - 6dae42f8-4368-4678-94ff-3960e28e3630/.default openid offline_access profile
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 45ef19b5-74e4-43ef-8937-1455a7034fb6
            Content-Length:
                - "2541"
            Content-Type:
                - application/x-www-form-urlencoded; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token
        method: POST
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 1405
        uncompressed: false
        body: '{"access_token":"TEST_ACCESS_TOKEN","expires_in":3599,"ext_expires_in":3599,"token_type":"Bearer"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - 45ef19b5-74e4-43ef-8937-1455a7034fb6
            Content-Length:
                - "1405"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-RvSJlAthIxU9BLHNwwqUXQ' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 00:18:09 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Clitelem:
                - 1,0,0,,
            X-Ms-Ests-Server:
                - 2.1.20106.4 - EUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 162.20102ms
0707010000008E000081A4000000000000000000000001687816E500002D82000000000000000000000000000000000000004B00000000kubelogin-0.2.10/pkg/internal/token/fixtures/client_secret_credential.yaml---
version: 2
interactions:
    - id: 0
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 1b92af2f-ae8a-450f-af74-a4ef00336305
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=https%3A%2F%2Flogin.microsoftonline.com%2F00000000-0000-0000-0000-000000000000%2Foauth2%2Fv2.0%2Fauthorize
        method: GET
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 980
        uncompressed: false
        body: '{"tenant_discovery_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 1b92af2f-ae8a-450f-af74-a4ef00336305
            Content-Length:
                - "980"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-W0pn7Aylpcwv_QbgA7aadw' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 03:53:28 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.20106.4 - NCUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 341.493421ms
    - id: 1
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - e3d5513c-38f5-466f-bb1b-ef08971e9535
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration
        method: GET
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 1753
        uncompressed: false
        body: '{"token_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/kerberos","tenant_region_scope":"NA","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - e3d5513c-38f5-466f-bb1b-ef08971e9535
            Content-Length:
                - "1753"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-uEUQF1eVnpgyCiCa8oyLCQ' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 03:53:28 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.20106.4 - SCUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 78.161229ms
    - id: 2
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 215
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: client_id=[REDACTED]&client_secret=[REDACTED]&grant_type=client_credentials&scope=6dae42f8-4368-4678-94ff-3960e28e3630%2F.default+openid+offline_access+profile
        form:
            client_id:
                - '[REDACTED]'
            client_secret:
                - '[REDACTED]'
            grant_type:
                - client_credentials
            scope:
                - 6dae42f8-4368-4678-94ff-3960e28e3630/.default openid offline_access profile
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 39e4c37b-acff-469e-bf35-2fc35ee16201
            Content-Length:
                - "215"
            Content-Type:
                - application/x-www-form-urlencoded; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token
        method: POST
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 1405
        uncompressed: false
        body: '{"access_token":"TEST_ACCESS_TOKEN","expires_in":3599,"ext_expires_in":3599,"token_type":"Bearer"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - 39e4c37b-acff-469e-bf35-2fc35ee16201
            Content-Length:
                - "1405"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-JIv-XV7UBaBFzdntLLrByw' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 03:53:28 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Clitelem:
                - 1,0,0,,
            X-Ms-Ests-Server:
                - 2.1.20106.4 - WUS3 ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 156.727923ms
0707010000008F000081A4000000000000000000000001687816E50000415E000000000000000000000000000000000000004900000000kubelogin-0.2.10/pkg/internal/token/fixtures/device_code_credential.yaml---
version: 2
interactions:
    - id: 0
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 51efc8c0-7007-4820-bfca-9053f7d39059
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration
        method: GET
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 1753
        uncompressed: false
        body: '{"token_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 51efc8c0-7007-4820-bfca-9053f7d39059
            Content-Length:
                - "1753"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-WnBbcnrrs82ARZRlz6SvYg' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 03:40:27 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.20106.4 - SCUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 242.809232ms
    - id: 1
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 130
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: client_id=[REDACTED]&scope=6dae42f8-4368-4678-94ff-3960e28e3630%2F.default+openid+offline_access+profile
        form:
            client_id:
                - '[REDACTED]'
            scope:
                - 6dae42f8-4368-4678-94ff-3960e28e3630/.default openid offline_access profile
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 8afe3606-ea18-4ef4-bbd0-1c13a67be41b
            Content-Length:
                - "130"
            Content-Type:
                - application/x-www-form-urlencoded; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/devicecode
        method: POST
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 473
        uncompressed: false
        body: '{"device_code":"[REDACTED]","expires_in":900,"interval":5,"message":"To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code BL6XB575V to authenticate.","user_code":"BL6XB575V","verification_uri":"https://microsoft.com/devicelogin"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - 8afe3606-ea18-4ef4-bbd0-1c13a67be41b
            Content-Length:
                - "473"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-bUONB85aTQuRnhxPDWJq4w' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 03:40:28 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Clitelem:
                - 1,0,0,,
            X-Ms-Ests-Server:
                - 2.1.20106.4 - WUS3 ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 220.915149ms
    - id: 2
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 387
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: client_id=[REDACTED]&client_info=1&device_code=[REDACTED]&grant_type=device_code&scope=6dae42f8-4368-4678-94ff-3960e28e3630%2F.default+openid+offline_access+profile
        form:
            client_id:
                - '[REDACTED]'
            client_info:
                - "1"
            device_code:
                - '[REDACTED]'
            grant_type:
                - device_code
            scope:
                - 6dae42f8-4368-4678-94ff-3960e28e3630/.default openid offline_access profile
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 243bab01-2a73-40fb-aae3-944b689626c9
            Content-Length:
                - "387"
            Content-Type:
                - application/x-www-form-urlencoded; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token
        method: POST
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 501
        uncompressed: false
        body: '{"error":"authorization_pending","error_description":"AADSTS70016: OAuth 2.0 device flow error. Authorization is pending. Continue polling. Trace ID: 214d175e-ce4c-48f4-ab71-a7c6bcb37300 Correlation ID: 8afe3606-ea18-4ef4-bbd0-1c13a67be41b Timestamp: 2025-02-19 03:40:30Z","error_codes":[70016],"timestamp":"2025-02-19 03:40:30Z","trace_id":"214d175e-ce4c-48f4-ab71-a7c6bcb37300","correlation_id":"8afe3606-ea18-4ef4-bbd0-1c13a67be41b","error_uri":"https://login.microsoftonline.com/error?code=70016"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - 8afe3606-ea18-4ef4-bbd0-1c13a67be41b
            Content-Length:
                - "501"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-HvxvCgEFrB8Yz6_Op0ICcw' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 03:40:29 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Clitelem:
                - 1,70016,0,,
            X-Ms-Ests-Server:
                - 2.1.20106.4 - EUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 400 Bad Request
        code: 400
        duration: 1.281511469s
    - id: 3
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 387
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: client_id=[REDACTED]&client_info=1&device_code=[REDACTED]&grant_type=device_code&scope=6dae42f8-4368-4678-94ff-3960e28e3630%2F.default+openid+offline_access+profile
        form:
            client_id:
                - '[REDACTED]'
            client_info:
                - "1"
            device_code:
                - '[REDACTED]'
            grant_type:
                - device_code
            scope:
                - 6dae42f8-4368-4678-94ff-3960e28e3630/.default openid offline_access profile
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - b533c512-bcd7-4833-a29d-fc051555e720
            Content-Length:
                - "387"
            Content-Type:
                - application/x-www-form-urlencoded; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token
        method: POST
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 5393
        uncompressed: false
        body: '{"access_token":"TEST_ACCESS_TOKEN","client_info":"eyJ1aWQiOiJjNzNjNmYyOC1hZTVmLTQxM2QtYTlhMi1lMTFlNWFmNjY4ZjgiLCJ1dGlkIjoiZTBiZDIzMjEtMDdmYS00Y2YwLTg3YjgtMDBhYTJhNzQ3MzI5In0","expires_in":5302,"ext_expires_in":5302,"id_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Imwzc1EtNTBjQ0g0eEJWWkxIVEd3blNSNzY4MCJ9.eyJhdWQiOiIwNGIwNzc5NS04ZGRiLTQ2MWEtYmJlZS0wMmY5ZTFiZjdiNDYiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vYzU0ZmFjODgtM2RkMy00NjFmLWE3YzQtOGEzNjhlMDM0MGIzL3YyLjAiLCJpYXQiOjE2MzcxOTEyMTIsIm5iZiI6MTYzNzE5MTIxMiwiZXhwIjoxNjM3MTk1MTEyLCJhaW8iOiJBVVFBdS84VEFBQUFQMExOZGNRUXQxNmJoSkFreXlBdjFoUGJuQVhtT0o3RXJDVHV4N0hNTjhHd2VMb2FYMWR1cDJhQ2Y0a0p5bDFzNmovSzF5R05DZmVIQlBXM21QUWlDdz09IiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvZTBiZDIzMjEtMDdmYS00Y2YwLTg3YjgtMDBhYTJhNzQ3MzI5LyIsIm5hbWUiOiJJZGVudGl0eSBUZXN0IFVzZXIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJpZGVudGl0eXRlc3R1c2VyQGF6dXJlc2Rrb3V0bG9vay5vbm1pY3Jvc29mdC5jb20iLCJyaCI6IjAuQVMwQWlLeFB4ZE05SDBhbnhJbzJqZ05BczVWM3NBVGJqUnBHdS00Qy1lR19lMFl0QUxFLiIsInN1YiI6ImMxYTBsY2xtbWxCYW9wc0MwVmlaLVpPMjFCT2dSUXE3SG9HRUtOOXloZnMiLCJ0aWQiOiJjNTRmYWM4OC0zZGQzLTQ2MWYtYTdjNC04YTM2OGUwMzQwYjMiLCJ1dGkiOiI5TXFOSWI5WjdrQy1QVHRtai11X0FBIiwidmVyIjoiMi4wIn0.hh5Exz9MBjTXrTuTZnz7vceiuQjcC_oRSTeBIC9tYgSO2c2sqQRpZi91qBZFQD9okayLPPKcwqXgEJD9p0-c4nUR5UQN7YSeDLmYtZUYMG79EsA7IMiQaiy94AyIe2E-oBDcLwFycGwh1iIOwwOwjbanmu2Dx3HfQx831lH9uVjagf0Aow0wTkTVCsedGSZvG-cRUceFLj-kFN-feFH3NuScuOfLR2Magf541pJda7X7oStwL_RNUFqjJFTdsiFV4e-VHK5qo--3oPU06z0rS9bosj0pFSATIVHrrS4gY7jiSvgMbG837CDBQkz5b08GUN5GlLN9jlygl1plBmbgww","refresh_token":"TEST_ACCESS_TOKEN","scope":"6dae42f8-4368-4678-94ff-3960e28e3630/user.read 6dae42f8-4368-4678-94ff-3960e28e3630/.default","token_type":"Bearer"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - 8afe3606-ea18-4ef4-bbd0-1c13a67be41b
            Content-Length:
                - "5393"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-RkPoga2NEeRg2bMx90ZRcg' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 03:40:48 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Clitelem:
                - 1,0,0,,
            X-Ms-Ests-Server:
                - 2.1.20106.4 - SCUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 507.460906ms
07070100000090000081A4000000000000000000000001687816E5000005C5000000000000000000000000000000000000004D00000000kubelogin-0.2.10/pkg/internal/token/fixtures/managedidentity_credential.yaml---
version: 2
interactions:
    - id: 0
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: 169.254.169.254
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Metadata:
                - "true"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
        url: http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&client_id=49a6a7eb-d4f9-444a-a216-7b966e31bb05&resource=6dae42f8-4368-4678-94ff-3960e28e3630
        method: GET
      response:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        transfer_encoding: []
        trailer: {}
        content_length: 2048
        uncompressed: false
        body: '{"access_token":"TEST_ACCESS_TOKEN","client_id":"49a6a7eb-d4f9-444a-a216-7b966e31bb05","expires_in":"86400","expires_on":"1740028277","ext_expires_in":"86399","not_before":"1739941577","resource":"6dae42f8-4368-4678-94ff-3960e28e3630","token_type":"Bearer"}'
        headers:
            Content-Length:
                - "2048"
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 05:11:17 GMT
            Server:
                - IMDS/150.870.65.1497
        status: 200 OK
        code: 200
        duration: 144.213894ms07070100000091000081A4000000000000000000000001687816E500002CAB000000000000000000000000000000000000004E00000000kubelogin-0.2.10/pkg/internal/token/fixtures/usernamepassword_credential.yaml---
version: 2
interactions:
    - id: 0
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 71d197c3-e97b-4a7b-b048-b485cc7228a8
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration
        method: GET
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 1753
        uncompressed: false
        body: '{"token_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/kerberos","tenant_region_scope":"NA","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 71d197c3-e97b-4a7b-b048-b485cc7228a8
            Content-Length:
                - "1753"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-fR-WzXKmTMoCTK7_B5nLxQ' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 03:49:11 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.20106.4 - SCUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 612.663239ms
    - id: 1
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 302ec217-0491-498d-96a5-fea43adb8e9a
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/common/UserRealm/user@example.com?api-version=1.0
        method: GET
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 192
        uncompressed: false
        body: '{"ver":"1.0","account_type":"Managed","domain_name":"azureredhatopenshift849.onmicrosoft.com","cloud_instance_name":"microsoftonline.com","cloud_audience_urn":"urn:federation:MicrosoftOnline"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - 302ec217-0491-498d-96a5-fea43adb8e9a
            Content-Disposition:
                - inline; filename=userrealm.json
            Content-Length:
                - "192"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-fDJMSqYR5s_RTU9lD3Bxiw' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 03:49:11 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.20106.4 - SCUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 124.006508ms
    - id: 2
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 243
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: client_id=[REDACTED]&client_info=1&grant_type=password&password=[REDACTED]&scope=6dae42f8-4368-4678-94ff-3960e28e3630%2F.default+openid+offline_access+profile&username=user@example.com
        form:
            client_id:
                - '[REDACTED]'
            client_info:
                - "1"
            grant_type:
                - password
            password:
                - '[REDACTED]'
            scope:
                - 6dae42f8-4368-4678-94ff-3960e28e3630/.default openid offline_access profile
            username:
                - '[REDACTED]'
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 10148fe9-b8bd-4c03-922f-8d351298ffa7
            Content-Length:
                - "243"
            Content-Type:
                - application/x-www-form-urlencoded; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token
        method: POST
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 635
        uncompressed: false
        body: '{"error":"invalid_grant","error_description":"AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access ''6dae42f8-4368-4678-94ff-3960e28e3630''. Trace ID: d828e473-16cc-480a-82f2-1278faf5e100 Correlation ID: 10148fe9-b8bd-4c03-922f-8d351298ffa7 Timestamp: 2025-02-19 03:49:12Z","error_codes":[50076],"timestamp":"2025-02-19 03:49:12Z","trace_id":"d828e473-16cc-480a-82f2-1278faf5e100","correlation_id":"10148fe9-b8bd-4c03-922f-8d351298ffa7","error_uri":"https://login.microsoftonline.com/error?code=50076","suberror":"basic_action"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - 10148fe9-b8bd-4c03-922f-8d351298ffa7
            Content-Length:
                - "635"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-_8miMZeHC5H3y1HPCLTxgw' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 03:49:11 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Clitelem:
                - 1,50076,0,,
            X-Ms-Ests-Server:
                - 2.1.20106.4 - NCUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 400 Bad Request
        code: 400
        duration: 229.357562ms
07070100000092000081A4000000000000000000000001687816E500002E8C000000000000000000000000000000000000004E00000000kubelogin-0.2.10/pkg/internal/token/fixtures/workloadidentity_credential.yaml---
version: 2
interactions:
    - id: 0
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 77c874a5-7647-48df-8307-d95f7b066109
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=https%3A%2F%2Flogin.microsoftonline.com%2F00000000-0000-0000-0000-000000000000%2Foauth2%2Fv2.0%2Fauthorize
        method: GET
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 980
        uncompressed: false
        body: '{"tenant_discovery_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 77c874a5-7647-48df-8307-d95f7b066109
            Content-Length:
                - "980"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-opJX6NtvONImkvZrrIpfPA' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 04:33:12 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.20051.5 - NCUS ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 340.052528ms
    - id: 1
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 0
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: ""
        form: {}
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 045b3798-fa6e-4fb7-bfb3-77208b03416a
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration
        method: GET
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 1753
        uncompressed: false
        body: '{"token_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token","token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt","client_secret_basic"],"jwks_uri":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/discovery/v2.0/keys","response_modes_supported":["query","fragment","form_post"],"subject_types_supported":["pairwise"],"id_token_signing_alg_values_supported":["RS256"],"response_types_supported":["code","id_token","code id_token","id_token token"],"scopes_supported":["openid","profile","email","offline_access"],"issuer":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0","request_uri_parameter_supported":false,"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo","authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/authorize","device_authorization_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/devicecode","http_logout_supported":true,"frontchannel_logout_supported":true,"end_session_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/logout","claims_supported":["sub","iss","cloud_instance_name","cloud_instance_host_name","cloud_graph_host_name","msgraph_host","aud","exp","iat","auth_time","acr","nonce","preferred_username","name","tid","ver","at_hash","c_hash","email"],"kerberos_endpoint":"https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/kerberos","tenant_region_scope":"WW","cloud_instance_name":"microsoftonline.com","cloud_graph_host_name":"graph.windows.net","msgraph_host":"graph.microsoft.com","rbac_url":"https://pas.windows.net"}'
        headers:
            Access-Control-Allow-Methods:
                - GET, OPTIONS
            Access-Control-Allow-Origin:
                - '*'
            Cache-Control:
                - max-age=86400, private
            Client-Request-Id:
                - 045b3798-fa6e-4fb7-bfb3-77208b03416a
            Content-Length:
                - "1753"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-9z_rTAo_nA4n9vWbGt2mFg' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 04:33:12 GMT
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Ests-Server:
                - 2.1.20106.4 - WUS3 ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 48.183889ms
    - id: 2
      request:
        proto: HTTP/1.1
        proto_major: 1
        proto_minor: 1
        content_length: 1649
        transfer_encoding: []
        trailer: {}
        host: login.microsoftonline.com
        remote_addr: ""
        request_uri: ""
        body: client_assertion=[REDACTED]&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_id=[REDACTED]&client_info=1&grant_type=client_credentials&scope=6dae42f8-4368-4678-94ff-3960e28e3630%2F.default+openid+offline_access+profile
        form:
            client_assertion:
                - '[REDACTED]'
            client_assertion_type:
                - urn:ietf:params:oauth:client-assertion-type:jwt-bearer
            client_id:
                - '[REDACTED]'
            client_info:
                - "1"
            grant_type:
                - client_credentials
            scope:
                - 6dae42f8-4368-4678-94ff-3960e28e3630/.default openid offline_access profile
        headers:
            Accept-Encoding:
                - gzip
            Client-Request-Id:
                - 4644ee85-42a4-4f5b-ac35-b5a3843a7ace
            Content-Length:
                - "1649"
            Content-Type:
                - application/x-www-form-urlencoded; charset=utf-8
            Return-Client-Request-Id:
                - "false"
            User-Agent:
                - azsdk-go-azidentity/v1.8.0 (go1.22.9; linux)
            X-Client-Cpu:
                - amd64
            X-Client-Os:
                - linux
            X-Client-Sku:
                - MSAL.Go
            X-Client-Ver:
                - 1.2.0
        url: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token
        method: POST
      response:
        proto: HTTP/2.0
        proto_major: 2
        proto_minor: 0
        transfer_encoding: []
        trailer: {}
        content_length: 1626
        uncompressed: false
        body: '{"access_token":"TEST_ACCESS_TOKEN","expires_in":86399,"ext_expires_in":86399,"token_type":"Bearer"}'
        headers:
            Cache-Control:
                - no-store, no-cache
            Client-Request-Id:
                - 4644ee85-42a4-4f5b-ac35-b5a3843a7ace
            Content-Length:
                - "1626"
            Content-Security-Policy-Report-Only:
                - object-src 'none'; base-uri 'self'; script-src 'self' 'nonce-U3JWdpDjbBzvPa_OFvgECA' 'unsafe-inline' 'unsafe-eval' https://*.msauth.net https://*.msftauth.net https://*.msftauthimages.net https://*.msauthimages.net https://*.msidentity.com https://*.microsoftonline-p.com https://*.microsoftazuread-sso.com https://*.azureedge.net https://*.outlook.com https://*.office.com https://*.office365.com https://*.microsoft.com https://*.bing.com 'report-sample'; report-uri https://csp.microsoft.com/report/ESTS-UX-All
            Content-Type:
                - application/json; charset=utf-8
            Date:
                - Wed, 19 Feb 2025 04:33:12 GMT
            Expires:
                - "-1"
            P3p:
                - CP="DSP CUR OTPi IND OTRi ONL FIN"
            Pragma:
                - no-cache
            Strict-Transport-Security:
                - max-age=31536000; includeSubDomains
            X-Content-Type-Options:
                - nosniff
            X-Ms-Clitelem:
                - 1,0,0,,
            X-Ms-Ests-Server:
                - 2.1.20106.4 - WUS3 ProdSlices
            X-Ms-Srs:
                - 1.P
            X-Xss-Protection:
                - "0"
        status: 200 OK
        code: 200
        duration: 267.028594ms
07070100000093000081A4000000000000000000000001687816E500000EDB000000000000000000000000000000000000003F00000000kubelogin-0.2.10/pkg/internal/token/githubactionscredential.gopackage token

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
)

type githubTokenResponse struct {
	Value string `json:"value"`
}

type GithubActionsCredential struct {
	client confidential.Client
}

var _ CredentialProvider = (*GithubActionsCredential)(nil)

func newGithubActionsCredential(opts *Options) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	cred := confidential.NewCredFromAssertionCallback(func(ctx context.Context, _ confidential.AssertionRequestOptions) (string, error) {
		return getGitHubToken(ctx)
	})

	o := []confidential.Option{
		confidential.WithInstanceDiscovery(!opts.DisableInstanceDiscovery),
	}
	if opts.httpClient != nil {
		o = append(o, confidential.WithHTTPClient(opts.httpClient))
	}
	client, err := confidential.New(
		fmt.Sprintf("%s%s/", opts.GetCloudConfiguration().ActiveDirectoryAuthorityHost, opts.TenantID),
		opts.ClientID, cred, o...)
	if err != nil {
		return nil, fmt.Errorf("failed to create github actions credential: %w", err)
	}

	return &GithubActionsCredential{client: client}, nil
}

func (c *GithubActionsCredential) Name() string {
	return "GithubActionsCredential"
}

func (c *GithubActionsCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *GithubActionsCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	result, err := c.client.AcquireTokenByCredential(ctx, opts.Scopes)
	if err != nil {
		return azcore.AccessToken{}, err
	}

	return azcore.AccessToken{Token: result.AccessToken, ExpiresOn: result.ExpiresOn}, nil
}

func (c *GithubActionsCredential) NeedAuthenticate() bool {
	return false
}

func getGitHubToken(ctx context.Context) (string, error) {
	reqToken := os.Getenv(actionsIDTokenRequestToken)
	reqURL := os.Getenv(actionsIDTokenRequestURL)

	if reqToken == "" || reqURL == "" {
		return "", errors.New("ACTIONS_ID_TOKEN_REQUEST_TOKEN or ACTIONS_ID_TOKEN_REQUEST_URL is not set")
	}

	u, err := url.Parse(reqURL)
	if err != nil {
		return "", fmt.Errorf("unable to parse ACTIONS_ID_TOKEN_REQUEST_URL: %w", err)
	}
	q := u.Query()
	q.Set("audience", azureADAudience)
	u.RawQuery = q.Encode()

	req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
	if err != nil {
		return "", err
	}

	// reference:
	// https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect
	req.Header.Set("Authorization", fmt.Sprintf("bearer %s", reqToken))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json; api-version=2.0")

	client := http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		var body string
		b, err := io.ReadAll(resp.Body)
		if err != nil {
			body = err.Error()
		} else {
			body = string(b)
		}

		return "", fmt.Errorf("github actions ID token request failed with status code: %d, response body: %s", resp.StatusCode, body)
	}

	var tokenResp githubTokenResponse
	if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
		return "", err
	}

	if tokenResp.Value == "" {
		return "", errors.New("github actions ID token is empty")
	}

	return tokenResp.Value, nil
}
07070100000094000081A4000000000000000000000001687816E500000B9E000000000000000000000000000000000000004400000000kubelogin-0.2.10/pkg/internal/token/githubactionscredential_test.gopackage token

import (
	"context"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewGithubActionsCredential(t *testing.T) {
	t.Run("valid options", func(t *testing.T) {
		opts := &Options{
			ClientID: "test-client-id",
			TenantID: "test-tenant-id",
		}

		cred, err := newGithubActionsCredential(opts)
		assert.NoError(t, err)
		assert.NotNil(t, cred)
		assert.Equal(t, "GithubActionsCredential", cred.Name())
	})

	t.Run("missing client ID", func(t *testing.T) {
		opts := &Options{
			TenantID: "test-tenant-id",
		}

		cred, err := newGithubActionsCredential(opts)
		assert.Error(t, err)
		assert.Nil(t, cred)
		assert.Equal(t, "client ID cannot be empty", err.Error())
	})

	t.Run("missing tenant ID", func(t *testing.T) {
		opts := &Options{
			ClientID: "test-client-id",
		}

		cred, err := newGithubActionsCredential(opts)
		assert.Error(t, err)
		assert.Nil(t, cred)
		assert.Equal(t, "tenant ID cannot be empty", err.Error())
	})
}

func TestGetGitHubToken(t *testing.T) {
	t.Run("valid token", func(t *testing.T) {
		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"value":"TEST_ACCESS_TOKEN"}`))
		}))
		defer ts.Close()

		os.Setenv("ACTIONS_ID_TOKEN_REQUEST_TOKEN", "test-token")
		os.Setenv("ACTIONS_ID_TOKEN_REQUEST_URL", ts.URL)

		token, err := getGitHubToken(context.Background())
		assert.NoError(t, err)
		assert.Equal(t, "TEST_ACCESS_TOKEN", token)
	})

	t.Run("invalid token", func(t *testing.T) {
		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"value":""}`))
		}))
		defer ts.Close()

		os.Setenv("ACTIONS_ID_TOKEN_REQUEST_TOKEN", "test-token")
		os.Setenv("ACTIONS_ID_TOKEN_REQUEST_URL", ts.URL)

		token, err := getGitHubToken(context.Background())
		assert.Error(t, err)
		assert.Equal(t, "", token)
		assert.Equal(t, "github actions ID token is empty", err.Error())
	})

	t.Run("http request failure", func(t *testing.T) {
		os.Setenv("ACTIONS_ID_TOKEN_REQUEST_TOKEN", "test-token")
		os.Setenv("ACTIONS_ID_TOKEN_REQUEST_URL", "http://invalid-url")

		token, err := getGitHubToken(context.Background())
		assert.Error(t, err)
		assert.Equal(t, "", token)
	})

	t.Run("invalid response from GitHub", func(t *testing.T) {
		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"invalid":"response"}`))
		}))
		defer ts.Close()

		os.Setenv("ACTIONS_ID_TOKEN_REQUEST_TOKEN", "test-token")
		os.Setenv("ACTIONS_ID_TOKEN_REQUEST_URL", ts.URL)

		token, err := getGitHubToken(context.Background())
		assert.Error(t, err)
		assert.Equal(t, "", token)
	})
}
07070100000095000081A4000000000000000000000001687816E5000008A0000000000000000000000000000000000000004400000000kubelogin-0.2.10/pkg/internal/token/interactivebrowsercredential.gopackage token

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache"
	"k8s.io/klog/v2"
)

type InteractiveBrowserCredential struct {
	cred *azidentity.InteractiveBrowserCredential
}

var _ CredentialProvider = (*InteractiveBrowserCredential)(nil)

func newInteractiveBrowserCredential(opts *Options, record azidentity.AuthenticationRecord) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	var (
		c   azidentity.Cache
		err error
	)
	if opts.UsePersistentCache {
		c, err = cache.New(nil)
		if err != nil {
			klog.V(5).Infof("failed to create cache: %v", err)
		}
	}

	azOpts := &azidentity.InteractiveBrowserCredentialOptions{
		ClientOptions:            azcore.ClientOptions{Cloud: opts.GetCloudConfiguration()},
		AuthenticationRecord:     record,
		Cache:                    c,
		ClientID:                 opts.ClientID,
		TenantID:                 opts.TenantID,
		DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
		RedirectURL:              opts.RedirectURL,
		LoginHint:                opts.LoginHint,
	}

	if opts.httpClient != nil {
		azOpts.ClientOptions.Transport = opts.httpClient
	}

	cred, err := azidentity.NewInteractiveBrowserCredential(azOpts)
	if err != nil {
		return nil, fmt.Errorf("failed to create interactive browser credential: %w", err)
	}
	return &InteractiveBrowserCredential{cred: cred}, nil
}

func (c *InteractiveBrowserCredential) Name() string {
	return "InteractiveBrowserCredential"
}

func (c *InteractiveBrowserCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return c.cred.Authenticate(ctx, opts)
}

func (c *InteractiveBrowserCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	return c.cred.GetToken(ctx, opts)
}

func (c *InteractiveBrowserCredential) NeedAuthenticate() bool {
	return true
}
07070100000096000081A4000000000000000000000001687816E500000440000000000000000000000000000000000000004900000000kubelogin-0.2.10/pkg/internal/token/interactivebrowsercredential_test.gopackage token

import (
	"context"
	"os"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/stretchr/testify/assert"
)

func TestInteractiveBrowserCredential_GetToken(t *testing.T) {
	if _, ok := os.LookupEnv("KUBELOGIN_MANUAL_TEST"); !ok {
		t.Skip("skipping test because KUBELOGIN_MANUAL_TEST is not set")
	}

	liveTestTenantID := os.Getenv("KUBELOGIN_LIVETEST_TENANT_ID")

	if liveTestTenantID == "" {
		t.Skip("skipping test because KUBELOGIN_LIVETEST_TENANT_ID is not set")
	}

	opts := &Options{
		ClientID: "80faf920-1908-4b52-b5ef-a8e7bedfc67a",
		ServerID: "6dae42f8-4368-4678-94ff-3960e28e3630",
		TenantID: liveTestTenantID,
	}
	record := azidentity.AuthenticationRecord{}
	cred, err := newInteractiveBrowserCredential(opts, record)
	if err != nil {
		t.Fatalf("failed to create credential: %v", err)
	}

	token, err := cred.GetToken(context.Background(), policy.TokenRequestOptions{
		Scopes: []string{opts.ServerID + "/.default"},
	})
	assert.NoError(t, err)
	assert.NotEmpty(t, token.Token)
}
07070100000097000081A4000000000000000000000001687816E500000912000000000000000000000000000000000000004B00000000kubelogin-0.2.10/pkg/internal/token/interactivebrowsercredentialwithpop.gopackage token

import (
	"context"
	"fmt"
	"time"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/kubelogin/pkg/internal/pop"
)

type InteractiveBrowserCredentialWithPoP struct {
	popClaims map[string]string
	options   *pop.MsalClientOptions
}

var _ CredentialProvider = (*InteractiveBrowserCredentialWithPoP)(nil)

func newInteractiveBrowserCredentialWithPoP(opts *Options) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	popClaimsMap, err := parsePoPClaims(opts.PoPTokenClaims)
	if err != nil {
		return nil, fmt.Errorf("unable to parse PoP claims: %w", err)
	}
	if len(popClaimsMap) == 0 {
		return nil, fmt.Errorf("number of pop claims is invalid: %d", len(popClaimsMap))
	}
	msalOpts := &pop.MsalClientOptions{
		Authority:                opts.GetCloudConfiguration().ActiveDirectoryAuthorityHost,
		ClientID:                 opts.ClientID,
		TenantID:                 opts.TenantID,
		DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
	}
	if opts.httpClient != nil {
		msalOpts.Options.Transport = opts.httpClient
	}
	return &InteractiveBrowserCredentialWithPoP{
		options:   msalOpts,
		popClaims: popClaimsMap,
	}, nil
}

func (c *InteractiveBrowserCredentialWithPoP) Name() string {
	return "InteractiveBrowserCredentialWithPoP"
}

func (c *InteractiveBrowserCredentialWithPoP) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *InteractiveBrowserCredentialWithPoP) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	token, expirationTimeUnix, err := pop.AcquirePoPTokenInteractive(
		ctx,
		c.popClaims,
		opts.Scopes,
		c.options,
	)
	if err != nil {
		return azcore.AccessToken{}, fmt.Errorf("failed to create PoP token using interactive login: %w", err)
	}
	return azcore.AccessToken{Token: token, ExpiresOn: time.Unix(expirationTimeUnix, 0)}, nil
}

func (c *InteractiveBrowserCredentialWithPoP) NeedAuthenticate() bool {
	return false
}
07070100000098000081A4000000000000000000000001687816E500000979000000000000000000000000000000000000005000000000kubelogin-0.2.10/pkg/internal/token/interactivebrowsercredentialwithpop_test.gopackage token

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNewInteractiveBrowserCredentialWithPoP(t *testing.T) {
	testCases := []struct {
		name           string
		opts           *Options
		expectErrorMsg string
		expectName     string
	}{
		{
			name: "valid options",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectName: "InteractiveBrowserCredentialWithPoP",
		},
		{
			name: "missing client ID",
			opts: &Options{
				TenantID:          "test-tenant-id",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectErrorMsg: "client ID cannot be empty",
		},
		{
			name: "missing tenant ID",
			opts: &Options{
				ClientID:          "test-client-id",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			expectErrorMsg: "tenant ID cannot be empty",
		},
		{
			name: "missing PoP claims",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				IsPoPTokenEnabled: true,
			},
			expectErrorMsg: "unable to parse PoP claims: failed to parse PoP token claims: no claims provided",
		},
		{
			name: "invalid PoP claims format",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "invalid-format",
			},
			expectErrorMsg: "unable to parse PoP claims: failed to parse PoP token claims. Ensure the claims are formatted as `key=value` with no extra whitespace",
		},
		{
			name: "missing required u-claim",
			opts: &Options{
				ClientID:          "test-client-id",
				TenantID:          "test-tenant-id",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "key=value",
			},
			expectErrorMsg: "unable to parse PoP claims: required u-claim not provided for PoP token flow. Please provide the ARM ID of the cluster in the format `u=<ARM_ID>`",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			cred, err := newInteractiveBrowserCredentialWithPoP(tc.opts)
			if tc.expectErrorMsg != "" {
				assert.Error(t, err)
				assert.Equal(t, tc.expectErrorMsg, err.Error())
				assert.Nil(t, cred)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, cred)
				assert.Equal(t, tc.expectName, cred.Name())
			}
		})
	}
}
07070100000099000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000002F00000000kubelogin-0.2.10/pkg/internal/token/mock_token0707010000009A000081A4000000000000000000000001687816E5000006C6000000000000000000000000000000000000004700000000kubelogin-0.2.10/pkg/internal/token/mock_token/execCredentialPlugin.go// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/Azure/kubelogin/pkg/internal/token (interfaces: ExecCredentialPlugin)
//
// Generated by this command:
//
//	mockgen -destination mock_token/execCredentialPlugin.go github.com/Azure/kubelogin/pkg/internal/token ExecCredentialPlugin
//

// Package mock_token is a generated GoMock package.
package mock_token

import (
	context "context"
	reflect "reflect"

	gomock "go.uber.org/mock/gomock"
)

// MockExecCredentialPlugin is a mock of ExecCredentialPlugin interface.
type MockExecCredentialPlugin struct {
	ctrl     *gomock.Controller
	recorder *MockExecCredentialPluginMockRecorder
}

// MockExecCredentialPluginMockRecorder is the mock recorder for MockExecCredentialPlugin.
type MockExecCredentialPluginMockRecorder struct {
	mock *MockExecCredentialPlugin
}

// NewMockExecCredentialPlugin creates a new mock instance.
func NewMockExecCredentialPlugin(ctrl *gomock.Controller) *MockExecCredentialPlugin {
	mock := &MockExecCredentialPlugin{ctrl: ctrl}
	mock.recorder = &MockExecCredentialPluginMockRecorder{mock}
	return mock
}

// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockExecCredentialPlugin) EXPECT() *MockExecCredentialPluginMockRecorder {
	return m.recorder
}

// Do mocks base method.
func (m *MockExecCredentialPlugin) Do(arg0 context.Context) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "Do", arg0)
	ret0, _ := ret[0].(error)
	return ret0
}

// Do indicates an expected call of Do.
func (mr *MockExecCredentialPluginMockRecorder) Do(arg0 any) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Do", reflect.TypeOf((*MockExecCredentialPlugin)(nil).Do), arg0)
}
0707010000009B000081A4000000000000000000000001687816E500000729000000000000000000000000000000000000004700000000kubelogin-0.2.10/pkg/internal/token/mock_token/execCredentialWriter.go// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/Azure/kubelogin/pkg/internal/token (interfaces: ExecCredentialWriter)
//
// Generated by this command:
//
//	mockgen -destination mock_token/execCredentialWriter.go github.com/Azure/kubelogin/pkg/internal/token ExecCredentialWriter
//

// Package mock_token is a generated GoMock package.
package mock_token

import (
	io "io"
	reflect "reflect"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	gomock "go.uber.org/mock/gomock"
)

// MockExecCredentialWriter is a mock of ExecCredentialWriter interface.
type MockExecCredentialWriter struct {
	ctrl     *gomock.Controller
	recorder *MockExecCredentialWriterMockRecorder
}

// MockExecCredentialWriterMockRecorder is the mock recorder for MockExecCredentialWriter.
type MockExecCredentialWriterMockRecorder struct {
	mock *MockExecCredentialWriter
}

// NewMockExecCredentialWriter creates a new mock instance.
func NewMockExecCredentialWriter(ctrl *gomock.Controller) *MockExecCredentialWriter {
	mock := &MockExecCredentialWriter{ctrl: ctrl}
	mock.recorder = &MockExecCredentialWriterMockRecorder{mock}
	return mock
}

// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockExecCredentialWriter) EXPECT() *MockExecCredentialWriterMockRecorder {
	return m.recorder
}

// Write mocks base method.
func (m *MockExecCredentialWriter) Write(arg0 azcore.AccessToken, arg1 io.Writer) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "Write", arg0, arg1)
	ret0, _ := ret[0].(error)
	return ret0
}

// Write indicates an expected call of Write.
func (mr *MockExecCredentialWriterMockRecorder) Write(arg0, arg1 any) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockExecCredentialWriter)(nil).Write), arg0, arg1)
}
0707010000009C000081A4000000000000000000000001687816E500000E31000000000000000000000000000000000000003B00000000kubelogin-0.2.10/pkg/internal/token/mock_token/provider.go// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/Azure/kubelogin/pkg/internal/token (interfaces: CredentialProvider)
//
// Generated by this command:
//
//	mockgen -destination mock_token/provider.go github.com/Azure/kubelogin/pkg/internal/token CredentialProvider
//

// Package mock_token is a generated GoMock package.
package mock_token

import (
	context "context"
	reflect "reflect"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	azidentity "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	gomock "go.uber.org/mock/gomock"
)

// MockCredentialProvider is a mock of CredentialProvider interface.
type MockCredentialProvider struct {
	ctrl     *gomock.Controller
	recorder *MockCredentialProviderMockRecorder
}

// MockCredentialProviderMockRecorder is the mock recorder for MockCredentialProvider.
type MockCredentialProviderMockRecorder struct {
	mock *MockCredentialProvider
}

// NewMockCredentialProvider creates a new mock instance.
func NewMockCredentialProvider(ctrl *gomock.Controller) *MockCredentialProvider {
	mock := &MockCredentialProvider{ctrl: ctrl}
	mock.recorder = &MockCredentialProviderMockRecorder{mock}
	return mock
}

// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockCredentialProvider) EXPECT() *MockCredentialProviderMockRecorder {
	return m.recorder
}

// Authenticate mocks base method.
func (m *MockCredentialProvider) Authenticate(arg0 context.Context, arg1 *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "Authenticate", arg0, arg1)
	ret0, _ := ret[0].(azidentity.AuthenticationRecord)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// Authenticate indicates an expected call of Authenticate.
func (mr *MockCredentialProviderMockRecorder) Authenticate(arg0, arg1 any) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Authenticate", reflect.TypeOf((*MockCredentialProvider)(nil).Authenticate), arg0, arg1)
}

// GetToken mocks base method.
func (m *MockCredentialProvider) GetToken(arg0 context.Context, arg1 policy.TokenRequestOptions) (azcore.AccessToken, error) {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "GetToken", arg0, arg1)
	ret0, _ := ret[0].(azcore.AccessToken)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetToken indicates an expected call of GetToken.
func (mr *MockCredentialProviderMockRecorder) GetToken(arg0, arg1 any) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetToken", reflect.TypeOf((*MockCredentialProvider)(nil).GetToken), arg0, arg1)
}

// Name mocks base method.
func (m *MockCredentialProvider) Name() string {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "Name")
	ret0, _ := ret[0].(string)
	return ret0
}

// Name indicates an expected call of Name.
func (mr *MockCredentialProviderMockRecorder) Name() *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockCredentialProvider)(nil).Name))
}

// NeedAuthenticate mocks base method.
func (m *MockCredentialProvider) NeedAuthenticate() bool {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "NeedAuthenticate")
	ret0, _ := ret[0].(bool)
	return ret0
}

// NeedAuthenticate indicates an expected call of NeedAuthenticate.
func (mr *MockCredentialProviderMockRecorder) NeedAuthenticate() *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NeedAuthenticate", reflect.TypeOf((*MockCredentialProvider)(nil).NeedAuthenticate))
}
0707010000009D000081A4000000000000000000000001687816E500000671000000000000000000000000000000000000003500000000kubelogin-0.2.10/pkg/internal/token/msicredential.gopackage token

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)

type ManagedIdentityCredential struct {
	cred *azidentity.ManagedIdentityCredential
}

var _ CredentialProvider = (*ManagedIdentityCredential)(nil)

func newManagedIdentityCredential(opts *Options) (CredentialProvider, error) {
	var id azidentity.ManagedIDKind
	if opts.ClientID != "" {
		id = azidentity.ClientID(opts.ClientID)
	} else if opts.IdentityResourceID != "" {
		id = azidentity.ResourceID(opts.IdentityResourceID)
	}

	azOpts := &azidentity.ManagedIdentityCredentialOptions{
		ClientOptions: azcore.ClientOptions{Cloud: opts.GetCloudConfiguration()},
		ID:            id,
	}

	if opts.httpClient != nil {
		azOpts.ClientOptions.Transport = opts.httpClient
	}

	cred, err := azidentity.NewManagedIdentityCredential(azOpts)
	if err != nil {
		return nil, fmt.Errorf("failed to create managed identity credential: %w", err)
	}
	return &ManagedIdentityCredential{cred: cred}, nil
}

func (c *ManagedIdentityCredential) Name() string {
	return "ManagedIdentityCredential"
}

func (c *ManagedIdentityCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *ManagedIdentityCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	return c.cred.GetToken(ctx, opts)
}

func (c *ManagedIdentityCredential) NeedAuthenticate() bool {
	return false
}
0707010000009E000081A4000000000000000000000001687816E5000003A1000000000000000000000000000000000000003A00000000kubelogin-0.2.10/pkg/internal/token/msicredential_test.gopackage token

import (
	"context"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/kubelogin/pkg/internal/testutils"
	"github.com/stretchr/testify/assert"
)

func TestManagedIdentityCredential_GetToken(t *testing.T) {
	rec, err := testutils.GetVCRHttpClient("fixtures/managedidentity_credential", testutils.TestTenantID)
	if err != nil {
		t.Fatalf("failed to create recorder: %v", err)
	}
	defer rec.Stop()

	opts := &Options{
		ClientID:   "49a6a7eb-d4f9-444a-a216-7b966e31bb05",
		ServerID:   testutils.TestServerID,
		httpClient: rec.GetDefaultClient(),
	}
	cred, err := newManagedIdentityCredential(opts)
	if err != nil {
		t.Fatalf("failed to create credential: %v", err)
	}

	token, err := cred.GetToken(context.Background(), policy.TokenRequestOptions{
		Scopes: []string{opts.ServerID + "/.default"},
	})
	assert.NoError(t, err)
	assert.Equal(t, testutils.TestToken, token.Token)
}
0707010000009F000081A4000000000000000000000001687816E5000035F3000000000000000000000000000000000000002F00000000kubelogin-0.2.10/pkg/internal/token/options.gopackage token

import (
	"fmt"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
	"github.com/Azure/kubelogin/pkg/internal/env"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"k8s.io/client-go/util/homedir"
)

type Options struct {
	LoginMethod                string
	ClientID                   string
	ClientSecret               string
	ClientCert                 string
	ClientCertPassword         string
	Username                   string
	Password                   string
	ServerID                   string
	TenantID                   string
	Environment                string
	IsLegacy                   bool
	Timeout                    time.Duration
	AuthRecordCacheDir         string
	authRecordCacheFile        string
	IdentityResourceID         string
	FederatedTokenFile         string
	AuthorityHost              string
	UseAzureRMTerraformEnv     bool
	IsPoPTokenEnabled          bool
	PoPTokenClaims             string
	DisableEnvironmentOverride bool
	UsePersistentCache         bool
	DisableInstanceDiscovery   bool
	httpClient                 *http.Client
	RedirectURL                string
	LoginHint                  string
}

const (
	defaultEnvironmentName = "AzurePublicCloud"

	DeviceCodeLogin        = "devicecode"
	InteractiveLogin       = "interactive"
	ServicePrincipalLogin  = "spn"
	ROPCLogin              = "ropc"
	MSILogin               = "msi"
	AzureCLILogin          = "azurecli"
	AzureDeveloperCLILogin = "azd"
	WorkloadIdentityLogin  = "workloadidentity"
)

var (
	supportedLogin            []string
	DefaultAuthRecordCacheDir = homedir.HomeDir() + "/.kube/cache/kubelogin/"
)

func init() {
	supportedLogin = []string{DeviceCodeLogin, InteractiveLogin, ServicePrincipalLogin, ROPCLogin, MSILogin, AzureCLILogin, AzureDeveloperCLILogin, WorkloadIdentityLogin}
}

func GetSupportedLogins() string {
	return strings.Join(supportedLogin, ", ")
}

func NewOptions(usePersistentCache bool) Options {
	envAuthRecordCacheDir := os.Getenv("KUBECACHEDIR")
	return Options{
		LoginMethod: DeviceCodeLogin,
		Environment: defaultEnvironmentName,
		AuthRecordCacheDir: func() string {
			if envAuthRecordCacheDir != "" {
				return envAuthRecordCacheDir
			}
			return DefaultAuthRecordCacheDir
		}(),
		UsePersistentCache: usePersistentCache,
	}
}

func (o *Options) AddFlags(fs *pflag.FlagSet) {
	fs.StringVarP(&o.LoginMethod, "login", "l", o.LoginMethod,
		fmt.Sprintf("Login method. Supported methods: %s. It may be specified in %s environment variable", GetSupportedLogins(), env.LoginMethod))
	fs.StringVar(&o.ClientID, "client-id", o.ClientID,
		fmt.Sprintf("AAD client application ID. It may be specified in %s or %s environment variable", env.KubeloginClientID, env.AzureClientID))
	fs.StringVar(&o.ClientSecret, "client-secret", o.ClientSecret,
		fmt.Sprintf("AAD client application secret. Used in spn login. It may be specified in %s or %s environment variable", env.KubeloginClientSecret, env.AzureClientSecret))
	fs.StringVar(&o.ClientCert, "client-certificate", o.ClientCert,
		fmt.Sprintf("AAD client cert in pfx. Used in spn login. It may be specified in %s or %s environment variable", env.KubeloginClientCertificatePath, env.AzureClientCertificatePath))
	fs.StringVar(&o.ClientCertPassword, "client-certificate-password", o.ClientCertPassword,
		fmt.Sprintf("Password for AAD client cert. Used in spn login. It may be specified in %s or %s environment variable", env.KubeloginClientCertificatePassword, env.AzureClientCertificatePassword))
	fs.StringVar(&o.Username, "username", o.Username,
		fmt.Sprintf("user name for ropc login flow. It may be specified in %s or %s environment variable", env.KubeloginROPCUsername, env.AzureUsername))
	fs.StringVar(&o.Password, "password", o.Password,
		fmt.Sprintf("password for ropc login flow. It may be specified in %s or %s environment variable", env.KubeloginROPCPassword, env.AzurePassword))
	fs.StringVar(&o.IdentityResourceID, "identity-resource-id", o.IdentityResourceID, "Managed Identity resource id.")
	fs.StringVar(&o.ServerID, "server-id", o.ServerID, "AAD server application ID")
	fs.StringVar(&o.FederatedTokenFile, "federated-token-file", o.FederatedTokenFile,
		fmt.Sprintf("Workload Identity federated token file. It may be specified in %s environment variable", env.AzureFederatedTokenFile))
	fs.StringVar(&o.AuthorityHost, "authority-host", o.AuthorityHost,
		fmt.Sprintf("Workload Identity authority host. It may be specified in %s environment variable", env.AzureAuthorityHost))
	fs.StringVar(&o.AuthRecordCacheDir, "token-cache-dir", o.AuthRecordCacheDir, "directory to cache authentication record")
	_ = fs.MarkDeprecated("token-cache-dir", "use --cache-dir instead")
	fs.StringVar(&o.AuthRecordCacheDir, "cache-dir", o.AuthRecordCacheDir, "directory to cache authentication record")
	fs.StringVarP(&o.TenantID, "tenant-id", "t", o.TenantID, fmt.Sprintf("AAD tenant ID. It may be specified in %s environment variable", env.AzureTenantID))
	fs.StringVarP(&o.Environment, "environment", "e", o.Environment, "Azure environment name")
	fs.BoolVar(&o.IsLegacy, "legacy", o.IsLegacy, "set to true to get token with 'spn:' prefix in audience claim")
	fs.BoolVar(&o.UseAzureRMTerraformEnv, "use-azurerm-env-vars", o.UseAzureRMTerraformEnv,
		"Use environment variable names of Terraform Azure Provider (ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_CLIENT_CERTIFICATE_PATH, ARM_CLIENT_CERTIFICATE_PASSWORD, ARM_TENANT_ID)")
	fs.BoolVar(&o.IsPoPTokenEnabled, "pop-enabled", o.IsPoPTokenEnabled, "set to true to use a PoP token for authentication or false to use a regular bearer token")
	fs.DurationVar(&o.Timeout, "timeout", 60*time.Second,
		fmt.Sprintf("Timeout duration for Azure CLI token requests. It may be specified in %s environment variable", "AZURE_CLI_TIMEOUT"))
	fs.StringVar(&o.PoPTokenClaims, "pop-claims", o.PoPTokenClaims, "contains a comma-separated list of claims to attach to the pop token in the format `key=val,key2=val2`. At minimum, specify the ARM ID of the cluster as `u=ARM_ID`")
	fs.BoolVar(&o.DisableEnvironmentOverride, "disable-environment-override", o.DisableEnvironmentOverride, "Enable or disable the use of env-variables. Default false")
	fs.BoolVar(&o.DisableInstanceDiscovery, "disable-instance-discovery", o.DisableInstanceDiscovery, "set to true to disable instance discovery in environments with their own simple Identity Provider (not AAD) that do not have instance metadata discovery endpoint. Default false")
	fs.StringVar(&o.RedirectURL, "redirect-url", o.RedirectURL, "The URL Microsoft Entra ID will redirect to with the access token. This is only used for interactive login. This is an optional parameter.")
	fs.StringVar(&o.LoginHint, "login-hint", o.LoginHint, "The login hint to pre-fill the username in the interactive login flow.")
}

func (o *Options) Validate() error {
	foundValidLoginMethod := false
	for _, v := range supportedLogin {
		if o.LoginMethod == v {
			foundValidLoginMethod = true
		}
	}

	if !foundValidLoginMethod {
		return fmt.Errorf("'%s' is not a supported login method. Supported method is one of %s", o.LoginMethod, GetSupportedLogins())
	}

	if o.AuthorityHost != "" {
		u, err := url.ParseRequestURI(o.AuthorityHost)
		if err != nil {
			return fmt.Errorf("authority host %q is not valid: %s", o.AuthorityHost, err)
		}
		if u.Scheme == "" || u.Host == "" {
			return fmt.Errorf("authority host %q is not valid", o.AuthorityHost)
		}
		if !strings.HasSuffix(o.AuthorityHost, "/") {
			return fmt.Errorf("authority host %q should have a trailing slash", o.AuthorityHost)
		}
	}

	// both of the following checks ensure that --pop-enabled and --pop-claims flags are provided together
	if o.IsPoPTokenEnabled && o.PoPTokenClaims == "" {
		return fmt.Errorf("if enabling pop token mode, please provide the pop-claims flag containing the PoP token claims as a comma-separated string: `u=popClaimHost,key1=val1`")
	}

	if o.PoPTokenClaims != "" && !o.IsPoPTokenEnabled {
		return fmt.Errorf("pop-enabled flag is required to use the PoP token feature. Please provide both pop-enabled and pop-claims flags")
	}

	if o.Timeout <= 0 {
		return fmt.Errorf("timeout must be greater than 0")
	}

	return nil
}

func (o *Options) UpdateFromEnv() {
	o.authRecordCacheFile = getAuthenticationRecordFileName(o)

	if o.DisableEnvironmentOverride {
		return
	}

	if o.UseAzureRMTerraformEnv {
		if v, ok := os.LookupEnv(env.TerraformClientID); ok {
			o.ClientID = v
		}
		if v, ok := os.LookupEnv(env.TerraformClientSecret); ok {
			o.ClientSecret = v
		}
		if v, ok := os.LookupEnv(env.TerraformClientCertificatePath); ok {
			o.ClientCert = v
		}
		if v, ok := os.LookupEnv(env.TerraformClientCertificatePassword); ok {
			o.ClientCertPassword = v
		}
		if v, ok := os.LookupEnv(env.TerraformTenantID); ok {
			o.TenantID = v
		}
	} else {
		if v, ok := os.LookupEnv(env.KubeloginClientID); ok {
			o.ClientID = v
		}
		if v, ok := os.LookupEnv(env.AzureClientID); ok {
			o.ClientID = v
		}
		if v, ok := os.LookupEnv(env.KubeloginClientSecret); ok {
			o.ClientSecret = v
		}
		if v, ok := os.LookupEnv(env.AzureClientSecret); ok {
			o.ClientSecret = v
		}
		if v, ok := os.LookupEnv(env.KubeloginClientCertificatePath); ok {
			o.ClientCert = v
		}
		if v, ok := os.LookupEnv(env.AzureClientCertificatePath); ok {
			o.ClientCert = v
		}
		if v, ok := os.LookupEnv(env.KubeloginClientCertificatePassword); ok {
			o.ClientCertPassword = v
		}
		if v, ok := os.LookupEnv(env.AzureClientCertificatePassword); ok {
			o.ClientCertPassword = v
		}
		if v, ok := os.LookupEnv(env.AzureTenantID); ok {
			o.TenantID = v
		}
	}

	if v, ok := os.LookupEnv(env.KubeloginROPCUsername); ok {
		o.Username = v
	}
	if v, ok := os.LookupEnv(env.AzureUsername); ok {
		o.Username = v
	}
	if v, ok := os.LookupEnv(env.KubeloginROPCPassword); ok {
		o.Password = v
	}
	if v, ok := os.LookupEnv(env.AzurePassword); ok {
		o.Password = v
	}
	if v, ok := os.LookupEnv(env.LoginMethod); ok {
		o.LoginMethod = v
	}

	if o.LoginMethod == WorkloadIdentityLogin {
		if v, ok := os.LookupEnv(env.AzureClientID); ok {
			o.ClientID = v
		}
		if v, ok := os.LookupEnv(env.AzureFederatedTokenFile); ok {
			o.FederatedTokenFile = v
		}
		if v, ok := os.LookupEnv(env.AzureAuthorityHost); ok {
			o.AuthorityHost = v
		}
	}
	if v, ok := os.LookupEnv("AZURE_CLI_TIMEOUT"); ok {
		if timeout, err := time.ParseDuration(v); err == nil {
			o.Timeout = timeout
		}
	}
}

func (o *Options) GetCloudConfiguration() cloud.Configuration {
	if o.AuthorityHost != "" {
		return cloud.Configuration{
			ActiveDirectoryAuthorityHost: o.AuthorityHost,
		}
	}

	switch strings.ToUpper(o.Environment) {
	case "AZURECLOUD":
		fallthrough
	case "AZUREPUBLIC":
		fallthrough
	case "AZUREPUBLICCLOUD":
		return cloud.AzurePublic
	case "AZUREUSGOVERNMENT":
		fallthrough
	case "AZUREUSGOVERNMENTCLOUD":
		return cloud.AzureGovernment
	case "AZURECHINACLOUD":
		return cloud.AzureChina
	}
	return cloud.AzurePublic
}

func (o *Options) ToString() string {
	azureConfigDir := os.Getenv("AZURE_CONFIG_DIR")

	parts := []string{
		fmt.Sprintf("Login Method: %s", o.LoginMethod),
		fmt.Sprintf("Environment: %s", o.Environment),
		fmt.Sprintf("TenantID: %s", o.TenantID),
		fmt.Sprintf("ServerID: %s", o.ServerID),
		fmt.Sprintf("ClientID: %s", o.ClientID),
		fmt.Sprintf("IsLegacy: %t", o.IsLegacy),
		fmt.Sprintf("msiResourceID: %s", o.IdentityResourceID),
		fmt.Sprintf("Timeout: %v", o.Timeout),
		fmt.Sprintf("authRecordCacheDir: %s", o.AuthRecordCacheDir),
		fmt.Sprintf("tokenauthRecordFile: %s", o.authRecordCacheFile),
		fmt.Sprintf("AZURE_CONFIG_DIR: %s", azureConfigDir),
		fmt.Sprintf("RedirectURL: %s", o.RedirectURL),
		fmt.Sprintf("LoginHint: %s", o.LoginHint),
	}

	return strings.Join(parts, ", ")
}

func getAuthenticationRecordFileName(o *Options) string {
	return filepath.Join(o.AuthRecordCacheDir, "auth.json")
}

// parsePoPClaims parses the pop token claims. Pop token claims are passed in as a
// comma-separated string in the format "key1=val1,key2=val2"
func parsePoPClaims(popClaims string) (map[string]string, error) {
	if strings.TrimSpace(popClaims) == "" {
		return nil, fmt.Errorf("failed to parse PoP token claims: no claims provided")
	}
	claimsArray := strings.Split(popClaims, ",")
	claimsMap := make(map[string]string)
	for _, claim := range claimsArray {
		claimPair := strings.Split(claim, "=")
		if len(claimPair) < 2 {
			return nil, fmt.Errorf("failed to parse PoP token claims. Ensure the claims are formatted as `key=value` with no extra whitespace")
		}
		key := strings.TrimSpace(claimPair[0])
		val := strings.TrimSpace(claimPair[1])
		if key == "" || val == "" {
			return nil, fmt.Errorf("failed to parse PoP token claims. Ensure the claims are formatted as `key=value` with no extra whitespace")
		}
		claimsMap[key] = val
	}
	if claimsMap["u"] == "" {
		return nil, fmt.Errorf("required u-claim not provided for PoP token flow. Please provide the ARM ID of the cluster in the format `u=<ARM_ID>`")
	}
	return claimsMap, nil
}

func (o *Options) AddCompletions(cmd *cobra.Command) {
	_ = cmd.RegisterFlagCompletionFunc("login", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
		return supportedLogin, cobra.ShellCompDirectiveNoFileComp
	})
	_ = cmd.MarkFlagFilename("client-certificate", "pfx", "cert")
	_ = cmd.MarkFlagFilename("federated-token-file", "")
	_ = cmd.MarkFlagDirname("token-cache-dir")

	cmd.Flags().VisitAll(func(flag *pflag.Flag) {
		// Set a default completion function if none was set. We don't look
		// up if it does already have one set, because Cobra does this for
		// us, and returns an error (which we ignore for this reason).
		_ = cmd.RegisterFlagCompletionFunc(flag.Name, cobra.NoFileCompletions)
	})
}
070701000000A0000081A4000000000000000000000001687816E500003822000000000000000000000000000000000000003400000000kubelogin-0.2.10/pkg/internal/token/options_test.gopackage token

import (
	"fmt"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/Azure/kubelogin/pkg/internal/env"
	"github.com/Azure/kubelogin/pkg/internal/testutils"
	"github.com/google/go-cmp/cmp"
	"github.com/spf13/pflag"
)

func TestOptions(t *testing.T) {
	t.Run("Default option should produce token cache file under default token cache directory", func(t *testing.T) {
		o := defaultOptions()
		o.AddFlags(&pflag.FlagSet{})
		o.UpdateFromEnv()
		if err := o.Validate(); err != nil {
			t.Fatalf("option validation failed: %s", err)
		}
		dir, _ := filepath.Split(o.authRecordCacheFile)
		if dir != DefaultAuthRecordCacheDir {
			t.Fatalf("token cache directory is expected to be %s, got %s", DefaultAuthRecordCacheDir, dir)
		}
	})

	t.Run("option with customized token cache dir should produce token cache file under specified token cache directory", func(t *testing.T) {
		o := defaultOptions()
		o.AuthRecordCacheDir = "/tmp/foo/"
		o.AddFlags(&pflag.FlagSet{})
		o.UpdateFromEnv()
		if err := o.Validate(); err != nil {
			t.Fatalf("option validation failed: %s", err)
		}
		dir, _ := filepath.Split(o.authRecordCacheFile)
		if dir != o.AuthRecordCacheDir {
			t.Fatalf("token cache directory is expected to be %s, got %s", o.AuthRecordCacheDir, dir)
		}
	})

	t.Run("invalid login method should return error", func(t *testing.T) {
		o := defaultOptions()
		o.LoginMethod = "unsupported"
		if err := o.Validate(); err == nil || !strings.Contains(err.Error(), "is not a supported login method") {
			t.Fatalf("unsupported login method should return unsupported error. got: %s", err)
		}
	})

	t.Run("pop-enabled flag should return error if pop-claims are not provided", func(t *testing.T) {
		o := defaultOptions()
		o.IsPoPTokenEnabled = true
		if err := o.Validate(); err == nil || !strings.Contains(err.Error(), "please provide the pop-claims flag") {
			t.Fatalf("pop-enabled with no pop claims should return missing pop-claims error. got: %s", err)
		}
	})

	t.Run("pop-claims flag should return error if pop-enabled is not provided", func(t *testing.T) {
		o := defaultOptions()
		o.PoPTokenClaims = "u=testhost"
		if err := o.Validate(); err == nil || !strings.Contains(err.Error(), "pop-enabled flag is required to use the PoP token feature") {
			t.Fatalf("pop-claims provided with no pop-enabled flag should return missing pop-enabled error. got: %s", err)
		}
	})

	t.Run("invalid authority host should return error", func(t *testing.T) {
		o := defaultOptions()
		o.AuthorityHost = "invalid"
		if err := o.Validate(); err == nil || !strings.Contains(err.Error(), `authority host "`+o.AuthorityHost+`" is not valid`) {
			t.Fatalf("invalid authority host should return invalid authority host error. got: %s", err)
		}
	})

	t.Run("setting authority host will set cloud.Configuration properly", func(t *testing.T) {
		o := defaultOptions()
		o.AuthorityHost = "https://login.example.com/"
		if err := o.Validate(); err != nil {
			t.Fatalf("setting authority host should not return error. got: %s", err)
		}
		if o.GetCloudConfiguration().ActiveDirectoryAuthorityHost != o.AuthorityHost {
			t.Fatalf("expected authority host to be %s, got %s",
				o.AuthorityHost, o.GetCloudConfiguration().ActiveDirectoryAuthorityHost)
		}
	})

	t.Run("default cloud.Configuration should be public azure", func(t *testing.T) {
		o := defaultOptions()
		if err := o.Validate(); err != nil {
			t.Fatalf("setting authority host should not return error. got: %s", err)
		}
		defaultAuthorityHost := "https://login.microsoftonline.com/"
		if o.GetCloudConfiguration().ActiveDirectoryAuthorityHost != defaultAuthorityHost {
			t.Fatalf("expected authority host to be %s, got %s",
				defaultAuthorityHost, o.GetCloudConfiguration().ActiveDirectoryAuthorityHost)
		}
	})

	t.Run("invalid timeout should return error", func(t *testing.T) {
		o := defaultOptions()
		o.Timeout = 0
		if err := o.Validate(); err == nil || !strings.Contains(err.Error(), "timeout must be greater than 0") {
			t.Fatalf("timeout of 0 should return error. got: %s", err)
		}
	})

	t.Run("valid PoP token claims should pass validation", func(t *testing.T) {
		o := defaultOptions()
		o.IsPoPTokenEnabled = true
		o.PoPTokenClaims = "u=testhost"
		if err := o.Validate(); err != nil {
			t.Fatalf("valid PoP token claims should not return error. got: %s", err)
		}
	})

}

func defaultOptions() Options {
	o := NewOptions(true)
	o.Timeout = 30 * time.Second
	return o
}

func TestOptionsWithEnvVars(t *testing.T) {
	const (
		clientID      = "clientID"
		clientSecret  = "clientSecret"
		certPath      = "certPath"
		certPassword  = "password"
		username      = "username"
		password      = "password"
		tenantID      = "tenantID"
		tokenFile     = "tokenFile"
		authorityHost = "authorityHost"
	)
	testCases := []struct {
		name        string
		envVarMap   map[string]string
		isTerraform bool
		expected    Options
	}{
		{
			name: "setting env var using legacy env var format",
			envVarMap: map[string]string{
				env.KubeloginClientID:                  clientID,
				env.KubeloginClientSecret:              clientSecret,
				env.KubeloginClientCertificatePath:     certPath,
				env.KubeloginClientCertificatePassword: certPassword,
				env.KubeloginROPCUsername:              username,
				env.KubeloginROPCPassword:              password,
				env.AzureTenantID:                      tenantID,
				env.LoginMethod:                        DeviceCodeLogin,
			},
			expected: Options{
				ClientID:            clientID,
				ClientSecret:        clientSecret,
				ClientCert:          certPath,
				ClientCertPassword:  certPassword,
				Username:            username,
				Password:            password,
				TenantID:            tenantID,
				LoginMethod:         DeviceCodeLogin,
				authRecordCacheFile: "auth.json",
				Timeout:             60 * time.Second,
			},
		},
		{
			name:        "setting env var using terraform env var format",
			isTerraform: true,
			envVarMap: map[string]string{
				env.TerraformClientID:                  clientID,
				env.TerraformClientSecret:              clientSecret,
				env.TerraformClientCertificatePath:     certPath,
				env.TerraformClientCertificatePassword: certPassword,
				env.TerraformTenantID:                  tenantID,
				env.LoginMethod:                        DeviceCodeLogin,
			},
			expected: Options{
				UseAzureRMTerraformEnv: true,
				ClientID:               clientID,
				ClientSecret:           clientSecret,
				ClientCert:             certPath,
				ClientCertPassword:     certPassword,
				TenantID:               tenantID,
				LoginMethod:            DeviceCodeLogin,
				authRecordCacheFile:    "auth.json",
				Timeout:                60 * time.Second,
			},
		},
		{
			name: "setting env var using azure sdk env var format",
			envVarMap: map[string]string{
				env.AzureClientID:                  clientID,
				env.AzureClientSecret:              clientSecret,
				env.AzureClientCertificatePath:     certPath,
				env.AzureClientCertificatePassword: certPassword,
				env.AzureUsername:                  username,
				env.AzurePassword:                  password,
				env.AzureTenantID:                  tenantID,
				env.LoginMethod:                    WorkloadIdentityLogin,
				env.AzureFederatedTokenFile:        tokenFile,
				env.AzureAuthorityHost:             authorityHost,
			},
			expected: Options{
				ClientID:            clientID,
				ClientSecret:        clientSecret,
				ClientCert:          certPath,
				ClientCertPassword:  certPassword,
				Username:            username,
				Password:            password,
				TenantID:            tenantID,
				LoginMethod:         WorkloadIdentityLogin,
				AuthorityHost:       authorityHost,
				FederatedTokenFile:  tokenFile,
				authRecordCacheFile: "auth.json",
				Timeout:             60 * time.Second,
			},
		},
	}
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			for k, v := range tc.envVarMap {
				t.Setenv(k, v)
			}
			o := Options{}
			if tc.isTerraform {
				o.UseAzureRMTerraformEnv = true
			}
			o.AddFlags(&pflag.FlagSet{})
			o.UpdateFromEnv()
			if !cmp.Equal(o, tc.expected, cmp.AllowUnexported(Options{})) {
				t.Fatalf("expected option: %+v, got %+v", tc.expected, o)
			}
		})
	}
}

func TestParsePoPClaims(t *testing.T) {
	testCases := []struct {
		name           string
		popClaims      string
		expectedError  error
		expectedClaims map[string]string
	}{
		{
			name:           "pop-claim parsing should fail on empty string",
			popClaims:      "",
			expectedError:  fmt.Errorf("failed to parse PoP token claims: no claims provided"),
			expectedClaims: nil,
		},
		{
			name:           "pop-claim parsing should fail on whitespace-only string",
			popClaims:      "	    ",
			expectedError:  fmt.Errorf("failed to parse PoP token claims: no claims provided"),
			expectedClaims: nil,
		},
		{
			name:           "pop-claim parsing should fail if claims are not provided in key=value format",
			popClaims:      "claim1=val1,claim2",
			expectedError:  fmt.Errorf("failed to parse PoP token claims. Ensure the claims are formatted as `key=value` with no extra whitespace"),
			expectedClaims: nil,
		},
		{
			name:           "pop-claim parsing should fail if claims are malformed",
			popClaims:      "claim1=  ",
			expectedError:  fmt.Errorf("failed to parse PoP token claims. Ensure the claims are formatted as `key=value` with no extra whitespace"),
			expectedClaims: nil,
		},
		{
			name:           "pop-claim parsing should fail if claims are malformed/commas only",
			popClaims:      ",,,,,,,,",
			expectedError:  fmt.Errorf("failed to parse PoP token claims. Ensure the claims are formatted as `key=value` with no extra whitespace"),
			expectedClaims: nil,
		},
		{
			name:           "pop-claim parsing should fail if u-claim is not provided",
			popClaims:      "1=2,3=4",
			expectedError:  fmt.Errorf("required u-claim not provided for PoP token flow. Please provide the ARM ID of the cluster in the format `u=<ARM_ID>`"),
			expectedClaims: nil,
		},
		{
			name:          "pop-claim parsing should succeed with u-claim and additional claims",
			popClaims:     "u=val1, claim2=val2, claim3=val3",
			expectedError: nil,
			expectedClaims: map[string]string{
				"u":      "val1",
				"claim2": "val2",
				"claim3": "val3",
			},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			claimsMap, err := parsePoPClaims(tc.popClaims)
			if err != nil {
				if !testutils.ErrorContains(err, tc.expectedError.Error()) {
					t.Fatalf("expected error: %+v, got error: %+v", tc.expectedError, err)
				}
			} else {
				if err != tc.expectedError {
					t.Fatalf("expected error: %+v, got error: %+v", tc.expectedError, err)
				}
			}
			if !cmp.Equal(claimsMap, tc.expectedClaims) {
				t.Fatalf("expected claims map to be %s, got map: %s", tc.expectedClaims, claimsMap)
			}
		})
	}
}

func TestDisableEnvironmentOverride(t *testing.T) {
	t.Run("TestDisableEnvironmentOverride", func(t *testing.T) {
		t.Setenv(env.KubeloginClientID, "client-id from env")
		o := Options{ClientID: "client-id from options"}
		o.DisableEnvironmentOverride = true
		o.UpdateFromEnv()
		if o.ClientID != "client-id from options" {
			t.Fatalf("expected client-id to be 'client-id from options', got %s", o.ClientID)
		}
	})

	t.Run("TestEnableEnvironmentOverride", func(t *testing.T) {
		t.Setenv(env.KubeloginClientID, "client-id from env")
		o := Options{ClientID: "client-id from options"}
		o.DisableEnvironmentOverride = false
		o.UpdateFromEnv()
		if o.ClientID != "client-id from env" {
			t.Fatalf("expected client-id to be 'client-id from env', got %s", o.ClientID)
		}
	})
}

func TestGetCloudConfiguration(t *testing.T) {
	testCases := []struct {
		name        string
		environment string
		authority   string
		expected    string
	}{
		{
			name:        "AZURECLOUD environment",
			environment: "AZURECLOUD",
			expected:    "https://login.microsoftonline.com/",
		},
		{
			name:        "AZUREPUBLIC environment",
			environment: "AZUREPUBLIC",
			expected:    "https://login.microsoftonline.com/",
		},
		{
			name:        "AZUREPUBLICCLOUD environment",
			environment: "AZUREPUBLICCLOUD",
			expected:    "https://login.microsoftonline.com/",
		},
		{
			name:        "AZUREUSGOVERNMENT environment",
			environment: "AZUREUSGOVERNMENT",
			expected:    "https://login.microsoftonline.us/",
		},
		{
			name:        "AZUREUSGOVERNMENTCLOUD environment",
			environment: "AZUREUSGOVERNMENTCLOUD",
			expected:    "https://login.microsoftonline.us/",
		},
		{
			name:        "AZURECHINACLOUD environment",
			environment: "AZURECHINACLOUD",
			expected:    "https://login.chinacloudapi.cn/",
		},
		{
			name:        "custom authority host",
			environment: "AZURECLOUD",
			authority:   "https://custom.authority.com/",
			expected:    "https://custom.authority.com/",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			o := Options{
				Environment:   tc.environment,
				AuthorityHost: tc.authority,
			}
			config := o.GetCloudConfiguration()
			if config.ActiveDirectoryAuthorityHost != tc.expected {
				t.Errorf("expected authority host %s, got %s", tc.expected, config.ActiveDirectoryAuthorityHost)
			}
		})
	}
}

func TestAuthorityHostValidation(t *testing.T) {
	testCases := []struct {
		name        string
		authority   string
		shouldError bool
	}{
		{
			name:        "valid authority with trailing slash",
			authority:   "https://login.example.com/",
			shouldError: false,
		},
		{
			name:        "valid authority without trailing slash",
			authority:   "https://login.example.com",
			shouldError: true,
		},
		{
			name:        "invalid authority without scheme",
			authority:   "login.example.com/",
			shouldError: true,
		},
		{
			name:        "invalid authority with malformed URL",
			authority:   "https://login example.com/",
			shouldError: true,
		},
		{
			name:        "empty authority",
			authority:   "",
			shouldError: false,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			o := defaultOptions()
			o.AuthorityHost = tc.authority
			err := o.Validate()
			if tc.shouldError && err == nil {
				t.Error("expected error but got none")
			}
			if !tc.shouldError && err != nil {
				t.Errorf("expected no error but got: %v", err)
			}
		})
	}
}
070701000000A1000081A4000000000000000000000001687816E5000008CC000000000000000000000000000000000000003000000000kubelogin-0.2.10/pkg/internal/token/provider.gopackage token

//go:generate sh -c "mockgen -destination mock_$GOPACKAGE/provider.go github.com/Azure/kubelogin/pkg/internal/token CredentialProvider"

import (
	"context"
	"errors"
	"os"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)

type CredentialProvider interface {
	GetToken(ctx context.Context, options policy.TokenRequestOptions) (azcore.AccessToken, error)

	Authenticate(ctx context.Context, options *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error)

	NeedAuthenticate() bool

	Name() string
}

func NewAzIdentityCredential(record azidentity.AuthenticationRecord, o *Options) (CredentialProvider, error) {
	switch o.LoginMethod {
	case AzureCLILogin:
		return newAzureCLICredential(o)

	case AzureDeveloperCLILogin:
		return newAzureDeveloperCLICredential(o)

	case DeviceCodeLogin:
		switch {
		case o.IsLegacy:
			return newADALDeviceCodeCredential(o)
		default:
			return newDeviceCodeCredential(o, record)
		}

	case InteractiveLogin:
		switch {
		case o.IsPoPTokenEnabled:
			return newInteractiveBrowserCredentialWithPoP(o)
		default:
			return newInteractiveBrowserCredential(o, record)
		}

	case MSILogin:
		return newManagedIdentityCredential(o)

	case ROPCLogin:
		switch {
		case o.IsPoPTokenEnabled:
			return newUsernamePasswordCredentialWithPoP(o)
		default:
			return newUsernamePasswordCredential(o, record)
		}

	case ServicePrincipalLogin:
		switch {
		case o.IsLegacy && o.ClientCert != "":
			return newADALClientCertCredential(o)
		case o.IsLegacy:
			return newADALClientSecretCredential(o)
		case o.ClientCert != "" && o.IsPoPTokenEnabled:
			return newClientCertificateCredentialWithPoP(o)
		case o.ClientCert != "":
			return newClientCertificateCredential(o)
		case o.IsPoPTokenEnabled:
			return newClientSecretCredentialWithPoP(o)
		default:
			return newClientSecretCredential(o)
		}

	case WorkloadIdentityLogin:
		switch {
		case os.Getenv(actionsIDTokenRequestToken) != "" && os.Getenv(actionsIDTokenRequestURL) != "":
			return newGithubActionsCredential(o)
		default:
			return newWorkloadIdentityCredential(o)
		}
	}

	return nil, errors.New("unsupported token provider")
}
070701000000A2000081A4000000000000000000000001687816E500000E2A000000000000000000000000000000000000003500000000kubelogin-0.2.10/pkg/internal/token/provider_test.gopackage token

import (
	"os"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/stretchr/testify/assert"
)

func TestNewAzIdentityCredential(t *testing.T) {
	certFile := "fixtures/cert.pem"

	tests := []struct {
		name       string
		options    *Options
		wantErr    bool
		errMessage string
	}{
		{
			name: "Azure CLI login",
			options: &Options{
				LoginMethod: AzureCLILogin,
				ServerID:    "server-id",
				TenantID:    "tenant-id",
			},
			wantErr: false,
		},
		{
			name: "Device code login",
			options: &Options{
				LoginMethod: DeviceCodeLogin,
				ServerID:    "server-id",
				TenantID:    "tenant-id",
				ClientID:    "client-id",
			},
			wantErr: false,
		},
		{
			name: "Legacy device code login",
			options: &Options{
				LoginMethod: DeviceCodeLogin,
				ServerID:    "server-id",
				TenantID:    "tenant-id",
				ClientID:    "client-id",
				IsLegacy:    true,
			},
			wantErr: false,
		},
		{
			name: "Interactive login with PoP",
			options: &Options{
				LoginMethod:       InteractiveLogin,
				ServerID:          "server-id",
				TenantID:          "tenant-id",
				ClientID:          "client-id",
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			wantErr: false,
		},
		{
			name: "MSI login",
			options: &Options{
				LoginMethod: MSILogin,
				ServerID:    "server-id",
			},
			wantErr: false,
		},
		{
			name: "Service Principal with client cert and PoP",
			options: &Options{
				LoginMethod:       ServicePrincipalLogin,
				ServerID:          "server-id",
				TenantID:          "tenant-id",
				ClientID:          "client-id",
				ClientCert:        certFile,
				IsPoPTokenEnabled: true,
				PoPTokenClaims:    "u=test-cluster",
			},
			wantErr: false,
		},
		{
			name: "Service Principal with client secret",
			options: &Options{
				LoginMethod:  ServicePrincipalLogin,
				ServerID:     "server-id",
				TenantID:     "tenant-id",
				ClientID:     "client-id",
				ClientSecret: "secret",
			},
			wantErr: false,
		},
		{
			name: "Unsupported login method",
			options: &Options{
				LoginMethod: "unsupported",
				ServerID:    "server-id",
			},
			wantErr:    true,
			errMessage: "unsupported token provider",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			record := azidentity.AuthenticationRecord{}
			provider, err := NewAzIdentityCredential(record, tt.options)

			if tt.wantErr {
				assert.Error(t, err)
				if tt.errMessage != "" {
					assert.Equal(t, tt.errMessage, err.Error())
				}
				assert.Nil(t, provider)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, provider)
			}
		})
	}
}

func TestNewAzIdentityCredentialWithWorkloadIdentity(t *testing.T) {
	// Setup environment variables
	os.Setenv("ACTIONS_ID_TOKEN_REQUEST_TOKEN", "token")
	os.Setenv("ACTIONS_ID_TOKEN_REQUEST_URL", "url")
	defer func() {
		os.Unsetenv("ACTIONS_ID_TOKEN_REQUEST_TOKEN")
		os.Unsetenv("ACTIONS_ID_TOKEN_REQUEST_URL")
	}()

	tests := []struct {
		name    string
		options *Options
		wantErr bool
	}{
		{
			name: "GitHub Actions Workload Identity",
			options: &Options{
				LoginMethod: WorkloadIdentityLogin,
				ServerID:    "server-id",
				TenantID:    "tenant-id",
				ClientID:    "client-id",
			},
			wantErr: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			record := azidentity.AuthenticationRecord{}
			provider, err := NewAzIdentityCredential(record, tt.options)

			if tt.wantErr {
				assert.Error(t, err)
				assert.Nil(t, provider)
			} else {
				assert.NoError(t, err)
				assert.NotNil(t, provider)
			}
		})
	}
}
070701000000A3000081A4000000000000000000000001687816E5000008BB000000000000000000000000000000000000004200000000kubelogin-0.2.10/pkg/internal/token/usernamepasswordcredential.gopackage token

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache"
	"k8s.io/klog/v2"
)

type UsernamePasswordCredential struct {
	cred *azidentity.UsernamePasswordCredential
}

var _ CredentialProvider = (*UsernamePasswordCredential)(nil)

func newUsernamePasswordCredential(opts *Options, record azidentity.AuthenticationRecord) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	if opts.Username == "" {
		return nil, fmt.Errorf("username cannot be empty")
	}
	if opts.Password == "" {
		return nil, fmt.Errorf("password cannot be empty")
	}
	var (
		c   azidentity.Cache
		err error
	)
	if opts.UsePersistentCache {
		c, err = cache.New(nil)
		if err != nil {
			klog.V(5).Infof("failed to create cache: %v", err)
		}
	}

	azOpts := &azidentity.UsernamePasswordCredentialOptions{
		ClientOptions:            azcore.ClientOptions{Cloud: opts.GetCloudConfiguration()},
		AuthenticationRecord:     record,
		Cache:                    c,
		DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
	}

	if opts.httpClient != nil {
		azOpts.ClientOptions.Transport = opts.httpClient
	}

	cred, err := azidentity.NewUsernamePasswordCredential(
		opts.TenantID, opts.ClientID, opts.Username, opts.Password,
		azOpts)
	if err != nil {
		return nil, fmt.Errorf("failed to create username password credential: %w", err)
	}
	return &UsernamePasswordCredential{cred: cred}, nil
}

func (c *UsernamePasswordCredential) Name() string {
	return "UsernamePasswordCredential"
}

func (c *UsernamePasswordCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return c.cred.Authenticate(ctx, opts)
}

func (c *UsernamePasswordCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	return c.cred.GetToken(ctx, opts)
}

func (c *UsernamePasswordCredential) NeedAuthenticate() bool {
	return true
}
070701000000A4000081A4000000000000000000000001687816E5000004F9000000000000000000000000000000000000004700000000kubelogin-0.2.10/pkg/internal/token/usernamepasswordcredential_test.gopackage token

import (
	"context"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/kubelogin/pkg/internal/testutils"
	"github.com/stretchr/testify/assert"
)

func TestUsernamePasswordCredential_GetToken(t *testing.T) {
	rec, err := testutils.GetVCRHttpClient("fixtures/usernamepassword_credential", testutils.TestTenantID)
	if err != nil {
		t.Fatalf("failed to create recorder: %v", err)
	}
	defer rec.Stop()

	opts := &Options{
		ClientID:   testutils.TestClientID,
		ServerID:   testutils.TestServerID,
		Username:   "user@example.come",
		Password:   "password",
		TenantID:   testutils.TestTenantID,
		httpClient: rec.GetDefaultClient(),
	}
	record := azidentity.AuthenticationRecord{}
	cred, err := newUsernamePasswordCredential(opts, record)
	if err != nil {
		t.Fatalf("failed to create credential: %v", err)
	}

	_, err = cred.GetToken(context.Background(), policy.TokenRequestOptions{
		Scopes: []string{opts.ServerID + "/.default"},
	})
	// our test environment requires MFA
	assert.ErrorContains(t, err, "AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access")
}
070701000000A5000081A4000000000000000000000001687816E500000A32000000000000000000000000000000000000004900000000kubelogin-0.2.10/pkg/internal/token/usernamepasswordcredentialwithpop.gopackage token

import (
	"context"
	"fmt"
	"time"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/kubelogin/pkg/internal/pop"
)

type UsernamePasswordCredentialWithPoP struct {
	popClaims map[string]string
	username  string
	password  string
	options   *pop.MsalClientOptions
}

var _ CredentialProvider = (*UsernamePasswordCredentialWithPoP)(nil)

func newUsernamePasswordCredentialWithPoP(opts *Options) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	if opts.Username == "" {
		return nil, fmt.Errorf("username cannot be empty")
	}
	if opts.Password == "" {
		return nil, fmt.Errorf("password cannot be empty")
	}
	popClaimsMap, err := parsePoPClaims(opts.PoPTokenClaims)
	if err != nil {
		return nil, fmt.Errorf("unable to parse PoP claims: %w", err)
	}
	if len(popClaimsMap) == 0 {
		return nil, fmt.Errorf("number of pop claims is invalid: %d", len(popClaimsMap))
	}
	msalOpts := &pop.MsalClientOptions{
		Authority:                opts.GetCloudConfiguration().ActiveDirectoryAuthorityHost,
		ClientID:                 opts.ClientID,
		TenantID:                 opts.TenantID,
		DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
	}
	if opts.httpClient != nil {
		msalOpts.Options.Transport = opts.httpClient
	}
	return &UsernamePasswordCredentialWithPoP{
		options:   msalOpts,
		popClaims: popClaimsMap,
		username:  opts.Username,
		password:  opts.Password,
	}, nil
}

func (c *UsernamePasswordCredentialWithPoP) Name() string {
	return "UsernamePasswordCredentialWithPoP"
}

func (c *UsernamePasswordCredentialWithPoP) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *UsernamePasswordCredentialWithPoP) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	token, expirationTimeUnix, err := pop.AcquirePoPTokenByUsernamePassword(
		ctx,
		c.popClaims,
		opts.Scopes,
		c.username,
		c.password,
		c.options,
	)
	if err != nil {
		return azcore.AccessToken{}, fmt.Errorf("failed to create PoP token using username and password credential: %w", err)
	}
	return azcore.AccessToken{Token: token, ExpiresOn: time.Unix(expirationTimeUnix, 0)}, nil
}

func (c *UsernamePasswordCredentialWithPoP) NeedAuthenticate() bool {
	return false
}
070701000000A6000081A4000000000000000000000001687816E50000098A000000000000000000000000000000000000004200000000kubelogin-0.2.10/pkg/internal/token/workloadidentitycredential.gopackage token

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache"
	"k8s.io/klog/v2"
)

const (
	actionsIDTokenRequestToken = "ACTIONS_ID_TOKEN_REQUEST_TOKEN"
	actionsIDTokenRequestURL   = "ACTIONS_ID_TOKEN_REQUEST_URL"
	azureADAudience            = "api://AzureADTokenExchange"
	defaultScope               = "/.default"
)

type WorkloadIdentityCredential struct {
	cred *azidentity.WorkloadIdentityCredential
}

var _ CredentialProvider = (*WorkloadIdentityCredential)(nil)

func newWorkloadIdentityCredential(opts *Options) (CredentialProvider, error) {
	if opts.ClientID == "" {
		return nil, fmt.Errorf("client ID cannot be empty")
	}
	if opts.TenantID == "" {
		return nil, fmt.Errorf("tenant ID cannot be empty")
	}
	if opts.FederatedTokenFile == "" {
		return nil, fmt.Errorf("federated token file cannot be empty")
	}
	var (
		c   azidentity.Cache
		err error
	)
	if opts.UsePersistentCache {
		c, err = cache.New(nil)
		if err != nil {
			klog.V(5).Infof("failed to create cache: %v", err)
		}
	}

	azOpts := &azidentity.WorkloadIdentityCredentialOptions{
		ClientOptions:            azcore.ClientOptions{Cloud: opts.GetCloudConfiguration()},
		Cache:                    c,
		ClientID:                 opts.ClientID,
		TenantID:                 opts.TenantID,
		TokenFilePath:            opts.FederatedTokenFile,
		DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
	}

	if opts.httpClient != nil {
		azOpts.ClientOptions.Transport = opts.httpClient
	}

	cred, err := azidentity.NewWorkloadIdentityCredential(azOpts)
	if err != nil {
		return nil, fmt.Errorf("failed to create workload identity credential: %w", err)
	}
	return &WorkloadIdentityCredential{cred: cred}, nil
}

func (c *WorkloadIdentityCredential) Name() string {
	return "WorkloadIdentityCredential"
}

func (c *WorkloadIdentityCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (azidentity.AuthenticationRecord, error) {
	return azidentity.AuthenticationRecord{}, errAuthenticateNotSupported
}

func (c *WorkloadIdentityCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
	return c.cred.GetToken(ctx, opts)
}

func (c *WorkloadIdentityCredential) NeedAuthenticate() bool {
	return false
}
070701000000A7000081A4000000000000000000000001687816E500000654000000000000000000000000000000000000004700000000kubelogin-0.2.10/pkg/internal/token/workloadidentitycredential_test.gopackage token

import (
	"context"
	"os"
	"path/filepath"
	"testing"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/kubelogin/pkg/internal/testutils"
	"github.com/stretchr/testify/assert"
)

func TestWorkloadIdentityCredential_GetToken(t *testing.T) {
	var tokenFile string

	liveTokenFile := os.Getenv("KUBELOGIN_LIVETEST_FEDERATED_TOKEN_FILE")
	if liveTokenFile == "" {
		tempDir, err := os.MkdirTemp("", "kubelogin")
		if err != nil {
			t.Fatalf("failed to create temp dir: %v", err)
		}

		tokenFile = filepath.Join(tempDir, "token")
		outFile, err := os.Create(tokenFile)
		if err != nil {
			t.Fatalf("failed to create token file: %v", err)
		}
		_, err = outFile.WriteString("[REDACTED]")
		if err != nil {
			t.Fatalf("failed to write token file: %v", err)
		}
		outFile.Close()
	} else {
		tokenFile = liveTokenFile
	}

	rec, err := testutils.GetVCRHttpClient("fixtures/workloadidentity_credential", testutils.TestTenantID)
	if err != nil {
		t.Fatalf("failed to create recorder: %v", err)
	}
	defer rec.Stop()

	opts := &Options{
		ClientID:           testutils.TestClientID,
		ServerID:           testutils.TestServerID,
		TenantID:           testutils.TestTenantID,
		FederatedTokenFile: tokenFile,
		httpClient:         rec.GetDefaultClient(),
	}
	cred, err := newWorkloadIdentityCredential(opts)
	if err != nil {
		t.Fatalf("failed to create credential: %v", err)
	}

	token, err := cred.GetToken(context.Background(), policy.TokenRequestOptions{
		Scopes: []string{opts.ServerID + "/.default"},
	})
	assert.NoError(t, err)
	assert.Equal(t, testutils.TestToken, token.Token)
}
070701000000A8000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001900000000kubelogin-0.2.10/pkg/pop070701000000A9000081A4000000000000000000000001687816E500000156000000000000000000000000000000000000002E00000000kubelogin-0.2.10/pkg/pop/msal_confidential.gopackage pop

import (
	"github.com/Azure/kubelogin/pkg/internal/pop"
)

// AcquirePoPTokenConfidential retrieves a Proof of Possession (PoP) token using confidential client credentials.
// It utilizes the internal pop.AcquirePoPTokenConfidential function to obtain the token.
var AcquirePoPTokenConfidential = pop.AcquirePoPTokenConfidential
070701000000AA000081A4000000000000000000000001687816E500000105000000000000000000000000000000000000002500000000kubelogin-0.2.10/pkg/pop/poptoken.gopackage pop

import "github.com/Azure/kubelogin/pkg/internal/pop"

// GetSwPoPKey retrieves a software Proof of Possession (PoP) key using RSA encryption.
// It utilizes the internal pop.GetSwPoPKey function to obtain the key.
var GetSwPoPKey = pop.GetSwPoPKey
070701000000AB000081A4000000000000000000000001687816E5000001E1000000000000000000000000000000000000002200000000kubelogin-0.2.10/pkg/pop/types.gopackage pop

import (
	"github.com/Azure/kubelogin/pkg/internal/pop"
)

// This is the MSAL implementation of AuthenticationScheme.
// For more details, see the MSAL repo interface:
// https://github.com/AzureAD/microsoft-authentication-library-for-go/blob/4a4dafcbcbd7d57a69ed3bc59760381232c2be9c/apps/internal/oauth/ops/authority/authority.go#L146
type PoPAuthenticationScheme = pop.PoPAuthenticationScheme

type SwKey = pop.SwKey

type MsalClientOptions = pop.MsalClientOptions
070701000000AC000041ED000000000000000000000002687816E500000000000000000000000000000000000000000000001B00000000kubelogin-0.2.10/pkg/token070701000000AD000081A4000000000000000000000001687816E5000003A1000000000000000000000000000000000000002600000000kubelogin-0.2.10/pkg/token/options.gopackage token

import "github.com/Azure/kubelogin/pkg/internal/token"

// list of supported login methods for library consumers

const (
	ServicePrincipalLogin = token.ServicePrincipalLogin
	MSILogin              = token.MSILogin
	WorkloadIdentityLogin = token.WorkloadIdentityLogin
)

// Options defines the options for getting token.
// This struct is a subset of internal/token.Options where its values are copied
// to internal type. See internal/token/options.go for details
type Options struct {
	LoginMethod string

	// shared login settings

	Environment string
	TenantID    string
	ServerID    string
	ClientID    string

	// for ServicePrincipalLogin

	ClientSecret       string
	ClientCert         string
	ClientCertPassword string
	IsPoPTokenEnabled  bool
	PoPTokenClaims     string

	// for MSILogin

	IdentityResourceID string

	// for WorkloadIdentityLogin

	AuthorityHost      string
	FederatedTokenFile string
}
070701000000AE000081A4000000000000000000000001687816E5000006FE000000000000000000000000000000000000002B00000000kubelogin-0.2.10/pkg/token/options_ctor.gopackage token

import (
	"os"

	"github.com/Azure/kubelogin/pkg/internal/env"
	"github.com/Azure/kubelogin/pkg/internal/token"
)

// OptionsWithEnv loads options from environment variables.
func OptionsWithEnv() *Options {
	// initial default values
	rv := &Options{
		LoginMethod:        os.Getenv(env.LoginMethod),
		TenantID:           os.Getenv(env.AzureTenantID),
		ClientID:           os.Getenv(env.KubeloginClientID),
		ClientSecret:       os.Getenv(env.KubeloginClientSecret),
		ClientCert:         os.Getenv(env.KubeloginClientCertificatePath),
		ClientCertPassword: os.Getenv(env.KubeloginClientCertificatePassword),
		AuthorityHost:      os.Getenv(env.AzureAuthorityHost),
		FederatedTokenFile: os.Getenv(env.AzureFederatedTokenFile),
	}

	// azure variant overrides
	if v, ok := os.LookupEnv(env.AzureClientID); ok {
		rv.ClientID = v
	}
	if v, ok := os.LookupEnv(env.AzureClientSecret); ok {
		rv.ClientSecret = v
	}
	if v, ok := os.LookupEnv(env.AzureClientCertificatePath); ok {
		rv.ClientCert = v
	}
	if v, ok := os.LookupEnv(env.AzureClientCertificatePassword); ok {
		rv.ClientCertPassword = v
	}

	return rv
}

func (opts *Options) toInternalOptions() *token.Options {
	return &token.Options{
		LoginMethod:        opts.LoginMethod,
		Environment:        opts.Environment,
		TenantID:           opts.TenantID,
		ServerID:           opts.ServerID,
		ClientID:           opts.ClientID,
		ClientSecret:       opts.ClientSecret,
		ClientCert:         opts.ClientCert,
		ClientCertPassword: opts.ClientCertPassword,
		IsPoPTokenEnabled:  opts.IsPoPTokenEnabled,
		PoPTokenClaims:     opts.PoPTokenClaims,
		IdentityResourceID: opts.IdentityResourceID,
		AuthorityHost:      opts.AuthorityHost,
		FederatedTokenFile: opts.FederatedTokenFile,
		UsePersistentCache: false,
	}
}
070701000000AF000081A4000000000000000000000001687816E50000143E000000000000000000000000000000000000003000000000kubelogin-0.2.10/pkg/token/options_ctor_test.gopackage token

import (
	"reflect"
	"testing"

	"github.com/Azure/kubelogin/pkg/internal/env"
	"github.com/Azure/kubelogin/pkg/internal/token"
	"github.com/stretchr/testify/assert"
)

func TestOptionsWithEnv(t *testing.T) {
	t.Run("no env vars", func(t *testing.T) {
		o := OptionsWithEnv()
		assert.Equal(t, &Options{}, o)
	})

	t.Run("with kubelogin variant env vars", func(t *testing.T) {
		for k, v := range map[string]string{
			env.LoginMethod:                        MSILogin,
			env.AzureTenantID:                      "tenant-id",
			env.KubeloginClientID:                  "client-id",
			env.KubeloginClientSecret:              "client-secret",
			env.KubeloginClientCertificatePath:     "client-cert-path",
			env.KubeloginClientCertificatePassword: "client-cert-password",
			env.AzureAuthorityHost:                 "authority-host",
			env.AzureFederatedTokenFile:            "federated-token-file",
		} {
			t.Setenv(k, v)
		}

		o := OptionsWithEnv()
		assert.Equal(t, &Options{
			LoginMethod:        MSILogin,
			TenantID:           "tenant-id",
			ClientID:           "client-id",
			ClientSecret:       "client-secret",
			ClientCert:         "client-cert-path",
			ClientCertPassword: "client-cert-password",
			AuthorityHost:      "authority-host",
			FederatedTokenFile: "federated-token-file",
		}, o)
	})

	t.Run("with azure variant env vars", func(t *testing.T) {
		for k, v := range map[string]string{
			env.LoginMethod:                        MSILogin,
			env.AzureTenantID:                      "tenant-id",
			env.KubeloginClientID:                  "client-id",
			env.AzureClientID:                      "azure-client-id",
			env.KubeloginClientSecret:              "client-secret",
			env.AzureClientSecret:                  "azure-client-secret",
			env.KubeloginClientCertificatePath:     "client-cert-path",
			env.AzureClientCertificatePath:         "azure-client-cert-path",
			env.KubeloginClientCertificatePassword: "client-cert-password",
			env.AzureClientCertificatePassword:     "azure-client-cert-password",
			env.AzureAuthorityHost:                 "authority-host",
			env.AzureFederatedTokenFile:            "federated-token-file",
		} {
			t.Setenv(k, v)
		}

		o := OptionsWithEnv()
		assert.Equal(t, &Options{
			LoginMethod:        MSILogin,
			TenantID:           "tenant-id",
			ClientID:           "azure-client-id",
			ClientSecret:       "azure-client-secret",
			ClientCert:         "azure-client-cert-path",
			ClientCertPassword: "azure-client-cert-password",
			AuthorityHost:      "authority-host",
			FederatedTokenFile: "federated-token-file",
		}, o)
	})
}

func TestOptions_toInternalOptions(t *testing.T) {
	t.Run("basic", func(t *testing.T) {
		o := &Options{
			LoginMethod:        "login-method",
			Environment:        "environment",
			TenantID:           "tenant-id",
			ServerID:           "server-id",
			ClientID:           "client-id",
			ClientSecret:       "client-secret",
			ClientCert:         "client-cert",
			ClientCertPassword: "client-cert-password",
			IsPoPTokenEnabled:  true,
			PoPTokenClaims:     "pop-token-claims",
			IdentityResourceID: "identity-resource-id",
			AuthorityHost:      "authority-host",
			FederatedTokenFile: "federated-token-file",
		}
		assert.Equal(t, &token.Options{
			LoginMethod:        "login-method",
			Environment:        "environment",
			TenantID:           "tenant-id",
			ServerID:           "server-id",
			ClientID:           "client-id",
			ClientSecret:       "client-secret",
			ClientCert:         "client-cert",
			ClientCertPassword: "client-cert-password",
			IsPoPTokenEnabled:  true,
			PoPTokenClaims:     "pop-token-claims",
			IdentityResourceID: "identity-resource-id",
			AuthorityHost:      "authority-host",
			FederatedTokenFile: "federated-token-file",
		}, o.toInternalOptions())
	})

	// this test uses reflection to ensure all fields in *Options
	// are copied to *token.Options without modification.
	t.Run("fields assignment", func(t *testing.T) {
		boolValue := true
		stringValue := "string-value"

		o := &Options{}

		// fill up all fields in *Options
		oType := reflect.TypeOf(o).Elem()
		oValue := reflect.ValueOf(o).Elem()
		for i := 0; i < oValue.NumField(); i++ {
			fieldValue := oValue.Field(i)
			fieldType := oType.Field(i)
			switch k := fieldType.Type.Kind(); k {
			case reflect.Bool:
				// set bool value
				fieldValue.SetBool(boolValue)
			case reflect.String:
				fieldValue.SetString(stringValue)
			default:
				t.Errorf("unexpected type: %s", k)
			}
		}

		internalOpts := o.toInternalOptions()
		assert.NotNil(t, internalOpts)

		internalOptsValue := reflect.ValueOf(internalOpts).Elem()
		for i := 0; i < oValue.NumField(); i++ {
			fieldType := oType.Field(i)
			t.Log(fieldType.Name)
			internalOptsFieldValue := internalOptsValue.FieldByName(fieldType.Name)
			switch k := fieldType.Type.Kind(); k {
			case reflect.Bool:
				assert.Equal(t, boolValue, internalOptsFieldValue.Bool(), "field: %s", fieldType.Name)
			case reflect.String:
				assert.Equal(t, stringValue, internalOptsFieldValue.String(), "field: %s", fieldType.Name)
			default:
				t.Errorf("unexpected type: %s", k)
			}
		}
	})
}
070701000000B0000081A4000000000000000000000001687816E5000003B3000000000000000000000000000000000000002700000000kubelogin-0.2.10/pkg/token/provider.gopackage token

import (
	"context"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/kubelogin/pkg/internal/token"
)

type tokenProviderShim struct {
	opts *token.Options
	cred token.CredentialProvider
}

var _ TokenProvider = (*tokenProviderShim)(nil)

func (tp *tokenProviderShim) GetAccessToken(ctx context.Context) (AccessToken, error) {
	tro := policy.TokenRequestOptions{
		TenantID: tp.opts.TenantID,
		Scopes:   []string{token.GetScope(tp.opts.ServerID)},
	}
	return tp.cred.GetToken(ctx, tro)
}

// GetTokenProvider returns a token provider based on the given options.
func GetTokenProvider(options *Options) (TokenProvider, error) {
	opts := options.toInternalOptions()
	cred, err := token.NewAzIdentityCredential(azidentity.AuthenticationRecord{}, opts)
	if err != nil {
		return nil, err
	}

	return &tokenProviderShim{
		cred: cred,
		opts: opts,
	}, nil
}
070701000000B1000081A4000000000000000000000001687816E500000872000000000000000000000000000000000000002C00000000kubelogin-0.2.10/pkg/token/provider_test.gopackage token

import (
	"context"
	"testing"
	"time"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/kubelogin/pkg/internal/token"
	"github.com/Azure/kubelogin/pkg/internal/token/mock_token"
	"github.com/stretchr/testify/assert"
	"go.uber.org/mock/gomock"
)

func TestGetTokenProvider(t *testing.T) {
	t.Run("invalid login method", func(t *testing.T) {
		opts := &Options{
			LoginMethod: "invalid-login-method",
		}
		tp, err := GetTokenProvider(opts)
		assert.Error(t, err)
		assert.Nil(t, tp)
	})

	t.Run("basic", func(t *testing.T) {
		opts := &Options{
			LoginMethod:        MSILogin,
			ClientID:           "client-id",
			IdentityResourceID: "identity-resource-id",
			ServerID:           "server-id",
		}
		tp, err := GetTokenProvider(opts)
		assert.NoError(t, err)
		assert.NotNil(t, tp)
	})
}

func TestTokenProviderShim_GetAccessToken(t *testing.T) {
	t.Run("failure case", func(t *testing.T) {
		mockCtrl := gomock.NewController(t)
		defer mockCtrl.Finish()

		credProvider := mock_token.NewMockCredentialProvider(mockCtrl)
		credProvider.EXPECT().GetToken(gomock.Any(), gomock.Any()).Return(azcore.AccessToken{}, assert.AnError)

		tp := &tokenProviderShim{
			cred: credProvider,
			opts: &token.Options{
				TenantID: "tenant-id",
				ServerID: "server-id",
			},
		}

		token, err := tp.GetAccessToken(context.Background())
		assert.Equal(t, AccessToken{}, token)
		assert.Equal(t, assert.AnError, err)
	})

	t.Run("success case", func(t *testing.T) {
		mockCtrl := gomock.NewController(t)
		defer mockCtrl.Finish()

		expectedToken := azcore.AccessToken{
			Token:     "access-token",
			ExpiresOn: time.Unix(1700000000, 0),
		}
		credProvider := mock_token.NewMockCredentialProvider(mockCtrl)
		credProvider.EXPECT().GetToken(gomock.Any(), gomock.Any()).Return(expectedToken, nil)

		tp := &tokenProviderShim{
			cred: credProvider,
			opts: &token.Options{
				TenantID: "tenant-id",
				ServerID: "server-id",
			},
		}

		token, err := tp.GetAccessToken(context.Background())
		assert.NoError(t, err)
		assert.Equal(t, expectedToken.Token, token.Token)
		assert.Equal(t, expectedToken.ExpiresOn, token.ExpiresOn)
	})
}
070701000000B2000081A4000000000000000000000001687816E50000019D000000000000000000000000000000000000002400000000kubelogin-0.2.10/pkg/token/types.gopackage token

import (
	"context"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
)

// AccessToken represents an Azure service bearer access token with expiry information.
type AccessToken = azcore.AccessToken

// TokenProvider provides access to tokens.
type TokenProvider interface {
	// GetAccessToken returns an access token from given settings.
	GetAccessToken(ctx context.Context) (AccessToken, error)
}
070701000000B3000081A4000000000000000000000001687816E5000006F8000000000000000000000000000000000000001C00000000kubelogin-0.2.10/version.gopackage main

import (
	"fmt"
	"runtime"
	"runtime/debug"
)

// gitTag provides the git tag used to build this binary.
// This is set via ldflags at build time, which normally set by the release pipeline.
// For go install binary, this value stays empty.
var gitTag string

type Version struct {
	Version   string
	GoVersion string
	BuildTime string
	Platform  string
}

func loadVersion() Version {
	rv := Version{
		Version:   "unknown",
		GoVersion: "unknown",
		BuildTime: "unknown",
		Platform:  runtime.GOOS + "/" + runtime.GOARCH,
	}
	if gitTag != "" {
		rv.Version = gitTag
	}

	buildInfo, ok := debug.ReadBuildInfo()
	if !ok {
		return rv
	}

	rv.GoVersion = buildInfo.GoVersion

	var (
		modified  bool
		revision  string
		buildTime string
	)
	for _, s := range buildInfo.Settings {
		if s.Value == "" {
			continue
		}

		switch s.Key {
		case "vcs.revision":
			revision = s.Value
		case "vcs.modified":
			modified = s.Value == "true"
		case "vcs.time":
			buildTime = s.Value
		}
	}

	// in Go install mode, this is a known issue that vcs information will not be available.
	// ref: https://github.com/golang/go/issues/51279
	// Fallback to use module version and stop here as vcs information is incomplete.
	if revision == "" {
		if buildInfo.Main.Version != "(devel)" {
			// fallback to use module version (legacy usage)
			rv.Version = buildInfo.Main.Version
		}

		return rv
	}

	if modified {
		revision += "-dirty"
	}
	if gitTag != "" {
		revision = gitTag + "/" + revision
	}
	rv.Version = revision

	if buildTime != "" {
		rv.BuildTime = buildTime
	}

	return rv
}

func (ver Version) String() string {
	return fmt.Sprintf(
		"\ngit hash: %s\nGo version: %s\nBuild time: %s\nPlatform: %s",
		ver.Version,
		ver.GoVersion,
		ver.BuildTime,
		ver.Platform,
	)
}
070701000000B4000081A4000000000000000000000001687816E5000000C7000000000000000000000000000000000000002100000000kubelogin-0.2.10/version_test.gopackage main

import "testing"

func Test_loadVersion(t *testing.T) {
	version := loadVersion()
	versionString := version.String()
	if versionString == "" {
		t.Errorf("versionString is empty")
	}
}
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!1337 blocks
openSUSE Build Service is sponsored by