Update go dependencies
This commit is contained in:
parent
15ffb51394
commit
bb4d483837
1621 changed files with 86368 additions and 284392 deletions
34
vendor/github.com/Azure/go-autorest/autorest/adal/README.md
generated
vendored
34
vendor/github.com/Azure/go-autorest/autorest/adal/README.md
generated
vendored
|
|
@ -218,6 +218,40 @@ if (err == nil) {
|
|||
}
|
||||
```
|
||||
|
||||
#### Username password authenticate
|
||||
|
||||
```Go
|
||||
spt, err := adal.NewServicePrincipalTokenFromUsernamePassword(
|
||||
oauthConfig,
|
||||
applicationID,
|
||||
username,
|
||||
password,
|
||||
resource,
|
||||
callbacks...)
|
||||
|
||||
if (err == nil) {
|
||||
token := spt.Token
|
||||
}
|
||||
```
|
||||
|
||||
#### Authorization code authenticate
|
||||
|
||||
``` Go
|
||||
spt, err := adal.NewServicePrincipalTokenFromAuthorizationCode(
|
||||
oauthConfig,
|
||||
applicationID,
|
||||
clientSecret,
|
||||
authorizationCode,
|
||||
redirectURI,
|
||||
resource,
|
||||
callbacks...)
|
||||
|
||||
err = spt.Refresh()
|
||||
if (err == nil) {
|
||||
token := spt.Token
|
||||
}
|
||||
```
|
||||
|
||||
### Command Line Tool
|
||||
|
||||
A command line tool is available in `cmd/adal.go` that can acquire a token for a given resource. It supports all flows mentioned above.
|
||||
|
|
|
|||
16
vendor/github.com/Azure/go-autorest/autorest/adal/config.go
generated
vendored
16
vendor/github.com/Azure/go-autorest/autorest/adal/config.go
generated
vendored
|
|
@ -32,8 +32,24 @@ type OAuthConfig struct {
|
|||
DeviceCodeEndpoint url.URL
|
||||
}
|
||||
|
||||
// IsZero returns true if the OAuthConfig object is zero-initialized.
|
||||
func (oac OAuthConfig) IsZero() bool {
|
||||
return oac == OAuthConfig{}
|
||||
}
|
||||
|
||||
func validateStringParam(param, name string) error {
|
||||
if len(param) == 0 {
|
||||
return fmt.Errorf("parameter '" + name + "' cannot be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewOAuthConfig returns an OAuthConfig with tenant specific urls
|
||||
func NewOAuthConfig(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) {
|
||||
if err := validateStringParam(activeDirectoryEndpoint, "activeDirectoryEndpoint"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// it's legal for tenantID to be empty so don't validate it
|
||||
const activeDirectoryEndpointTemplate = "%s/oauth2/%s?api-version=%s"
|
||||
u, err := url.Parse(activeDirectoryEndpoint)
|
||||
if err != nil {
|
||||
|
|
|
|||
44
vendor/github.com/Azure/go-autorest/autorest/adal/config_test.go
generated
vendored
44
vendor/github.com/Azure/go-autorest/autorest/adal/config_test.go
generated
vendored
|
|
@ -1,44 +0,0 @@
|
|||
package adal
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewOAuthConfig(t *testing.T) {
|
||||
const testActiveDirectoryEndpoint = "https://login.test.com"
|
||||
const testTenantID = "tenant-id-test"
|
||||
|
||||
config, err := NewOAuthConfig(testActiveDirectoryEndpoint, testTenantID)
|
||||
if err != nil {
|
||||
t.Fatalf("autorest/adal: Unexpected error while creating oauth configuration for tenant: %v.", err)
|
||||
}
|
||||
|
||||
expected := "https://login.test.com/tenant-id-test/oauth2/authorize?api-version=1.0"
|
||||
if config.AuthorizeEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal: Incorrect authorize url for Tenant from Environment. expected(%s). actual(%v).", expected, config.AuthorizeEndpoint)
|
||||
}
|
||||
|
||||
expected = "https://login.test.com/tenant-id-test/oauth2/token?api-version=1.0"
|
||||
if config.TokenEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal: Incorrect authorize url for Tenant from Environment. expected(%s). actual(%v).", expected, config.TokenEndpoint)
|
||||
}
|
||||
|
||||
expected = "https://login.test.com/tenant-id-test/oauth2/devicecode?api-version=1.0"
|
||||
if config.DeviceCodeEndpoint.String() != expected {
|
||||
t.Fatalf("autorest/adal Incorrect devicecode url for Tenant from Environment. expected(%s). actual(%v).", expected, config.DeviceCodeEndpoint)
|
||||
}
|
||||
}
|
||||
330
vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken_test.go
generated
vendored
330
vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken_test.go
generated
vendored
|
|
@ -1,330 +0,0 @@
|
|||
package adal
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
const (
|
||||
TestResource = "SomeResource"
|
||||
TestClientID = "SomeClientID"
|
||||
TestTenantID = "SomeTenantID"
|
||||
TestActiveDirectoryEndpoint = "https://login.test.com/"
|
||||
)
|
||||
|
||||
var (
|
||||
testOAuthConfig, _ = NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID)
|
||||
TestOAuthConfig = *testOAuthConfig
|
||||
)
|
||||
|
||||
const MockDeviceCodeResponse = `
|
||||
{
|
||||
"device_code": "10000-40-1234567890",
|
||||
"user_code": "ABCDEF",
|
||||
"verification_url": "http://aka.ms/deviceauth",
|
||||
"expires_in": "900",
|
||||
"interval": "0"
|
||||
}
|
||||
`
|
||||
|
||||
const MockDeviceTokenResponse = `{
|
||||
"access_token": "accessToken",
|
||||
"refresh_token": "refreshToken",
|
||||
"expires_in": "1000",
|
||||
"expires_on": "2000",
|
||||
"not_before": "3000",
|
||||
"resource": "resource",
|
||||
"token_type": "type"
|
||||
}
|
||||
`
|
||||
|
||||
func TestDeviceCodeIncludesResource(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
sender.AppendResponse(mocks.NewResponseWithContent(MockDeviceCodeResponse))
|
||||
|
||||
code, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
|
||||
if err != nil {
|
||||
t.Fatalf("adal: unexpected error initiating device auth")
|
||||
}
|
||||
|
||||
if code.Resource != TestResource {
|
||||
t.Fatalf("adal: InitiateDeviceAuth failed to stash the resource in the DeviceCode struct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceCodeReturnsErrorIfSendingFails(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
sender.SetError(fmt.Errorf("this is an error"))
|
||||
|
||||
_, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
|
||||
if err == nil || !strings.Contains(err.Error(), errCodeSendingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeSendingFails, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceCodeReturnsErrorIfBadRequest(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody("doesn't matter")
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
|
||||
if err == nil || !strings.Contains(err.Error(), errCodeHandlingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeHandlingFails, err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceCodeReturnsErrorIfCannotDeserializeDeviceCode(t *testing.T) {
|
||||
gibberishJSON := strings.Replace(MockDeviceCodeResponse, "expires_in", "\":, :gibberish", -1)
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(gibberishJSON)
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
|
||||
|
||||
_, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
|
||||
if err == nil || !strings.Contains(err.Error(), errCodeHandlingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeHandlingFails, err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceCodeReturnsErrorIfEmptyDeviceCode(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody("")
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
|
||||
|
||||
_, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource)
|
||||
if err != ErrDeviceCodeEmpty {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", ErrDeviceCodeEmpty, err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func deviceCode() *DeviceCode {
|
||||
var deviceCode DeviceCode
|
||||
_ = json.Unmarshal([]byte(MockDeviceCodeResponse), &deviceCode)
|
||||
deviceCode.Resource = TestResource
|
||||
deviceCode.ClientID = TestClientID
|
||||
return &deviceCode
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturns(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(MockDeviceTokenResponse)
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != nil {
|
||||
t.Fatalf("adal: got error unexpectedly")
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfSendingFails(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
sender.SetError(fmt.Errorf("this is an error"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err == nil || !strings.Contains(err.Error(), errTokenSendingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenSendingFails, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfServerError(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody("")
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusInternalServerError, "Internal Server Error"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err == nil || !strings.Contains(err.Error(), errTokenHandlingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenHandlingFails, err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfCannotDeserializeDeviceToken(t *testing.T) {
|
||||
gibberishJSON := strings.Replace(MockDeviceTokenResponse, "expires_in", ";:\"gibberish", -1)
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(gibberishJSON)
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err == nil || !strings.Contains(err.Error(), errTokenHandlingFails) {
|
||||
t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenHandlingFails, err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func errorDeviceTokenResponse(message string) string {
|
||||
return `{ "error": "` + message + `" }`
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfAuthorizationPending(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(errorDeviceTokenResponse("authorization_pending"))
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := CheckForUserCompletion(sender, deviceCode())
|
||||
if err != ErrDeviceAuthorizationPending {
|
||||
t.Fatalf("!!!")
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfSlowDown(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(errorDeviceTokenResponse("slow_down"))
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := CheckForUserCompletion(sender, deviceCode())
|
||||
if err != ErrDeviceSlowDown {
|
||||
t.Fatalf("!!!")
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
type deviceTokenSender struct {
|
||||
errorString string
|
||||
attempts int
|
||||
}
|
||||
|
||||
func newDeviceTokenSender(deviceErrorString string) *deviceTokenSender {
|
||||
return &deviceTokenSender{errorString: deviceErrorString, attempts: 0}
|
||||
}
|
||||
|
||||
func (s *deviceTokenSender) Do(req *http.Request) (*http.Response, error) {
|
||||
var resp *http.Response
|
||||
if s.attempts < 1 {
|
||||
s.attempts++
|
||||
resp = mocks.NewResponseWithContent(errorDeviceTokenResponse(s.errorString))
|
||||
} else {
|
||||
resp = mocks.NewResponseWithContent(MockDeviceTokenResponse)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// since the above only exercise CheckForUserCompletion, we repeat the test here,
|
||||
// but with the intent of showing that WaitForUserCompletion loops properly.
|
||||
func TestDeviceTokenSucceedsWithIntermediateAuthPending(t *testing.T) {
|
||||
sender := newDeviceTokenSender("authorization_pending")
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error occurred")
|
||||
}
|
||||
}
|
||||
|
||||
// same as above but with SlowDown now
|
||||
func TestDeviceTokenSucceedsWithIntermediateSlowDown(t *testing.T) {
|
||||
sender := newDeviceTokenSender("slow_down")
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error occurred")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfAccessDenied(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(errorDeviceTokenResponse("access_denied"))
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != ErrDeviceAccessDenied {
|
||||
t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceAccessDenied.Error(), err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfCodeExpired(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(errorDeviceTokenResponse("code_expired"))
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != ErrDeviceCodeExpired {
|
||||
t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceCodeExpired.Error(), err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorForUnknownError(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody(errorDeviceTokenResponse("unknown_error"))
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err == nil {
|
||||
t.Fatalf("failed to get error")
|
||||
}
|
||||
if err != ErrDeviceGeneric {
|
||||
t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceGeneric.Error(), err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTokenReturnsErrorIfTokenEmptyAndStatusOK(t *testing.T) {
|
||||
sender := mocks.NewSender()
|
||||
body := mocks.NewBody("")
|
||||
sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK"))
|
||||
|
||||
_, err := WaitForUserCompletion(sender, deviceCode())
|
||||
if err != ErrOAuthTokenEmpty {
|
||||
t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrOAuthTokenEmpty.Error(), err.Error())
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("response body was left open!")
|
||||
}
|
||||
}
|
||||
171
vendor/github.com/Azure/go-autorest/autorest/adal/persist_test.go
generated
vendored
171
vendor/github.com/Azure/go-autorest/autorest/adal/persist_test.go
generated
vendored
|
|
@ -1,171 +0,0 @@
|
|||
package adal
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const MockTokenJSON string = `{
|
||||
"access_token": "accessToken",
|
||||
"refresh_token": "refreshToken",
|
||||
"expires_in": "1000",
|
||||
"expires_on": "2000",
|
||||
"not_before": "3000",
|
||||
"resource": "resource",
|
||||
"token_type": "type"
|
||||
}`
|
||||
|
||||
var TestToken = Token{
|
||||
AccessToken: "accessToken",
|
||||
RefreshToken: "refreshToken",
|
||||
ExpiresIn: "1000",
|
||||
ExpiresOn: "2000",
|
||||
NotBefore: "3000",
|
||||
Resource: "resource",
|
||||
Type: "type",
|
||||
}
|
||||
|
||||
func writeTestTokenFile(t *testing.T, suffix string, contents string) *os.File {
|
||||
f, err := ioutil.TempFile(os.TempDir(), suffix)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: unexpected error when creating temp file: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.Write([]byte(contents))
|
||||
if err != nil {
|
||||
t.Fatalf("azure: unexpected error when writing temp test file: %v", err)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func TestLoadToken(t *testing.T) {
|
||||
f := writeTestTokenFile(t, "testloadtoken", MockTokenJSON)
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
expectedToken := TestToken
|
||||
actualToken, err := LoadToken(f.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("azure: unexpected error loading token from file: %v", err)
|
||||
}
|
||||
|
||||
if *actualToken != expectedToken {
|
||||
t.Fatalf("azure: failed to decode properly expected(%v) actual(%v)", expectedToken, *actualToken)
|
||||
}
|
||||
|
||||
// test that LoadToken closes the file properly
|
||||
err = SaveToken(f.Name(), 0600, *actualToken)
|
||||
if err != nil {
|
||||
t.Fatalf("azure: could not save token after LoadToken: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadTokenFailsBadPath(t *testing.T) {
|
||||
_, err := LoadToken("/tmp/this_file_should_never_exist_really")
|
||||
expectedSubstring := "failed to open file"
|
||||
if err == nil || !strings.Contains(err.Error(), expectedSubstring) {
|
||||
t.Fatalf("azure: failed to get correct error expected(%s) actual(%s)", expectedSubstring, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadTokenFailsBadJson(t *testing.T) {
|
||||
gibberishJSON := strings.Replace(MockTokenJSON, "expires_on", ";:\"gibberish", -1)
|
||||
f := writeTestTokenFile(t, "testloadtokenfailsbadjson", gibberishJSON)
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
_, err := LoadToken(f.Name())
|
||||
expectedSubstring := "failed to decode contents of file"
|
||||
if err == nil || !strings.Contains(err.Error(), expectedSubstring) {
|
||||
t.Fatalf("azure: failed to get correct error expected(%s) actual(%s)", expectedSubstring, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func token() *Token {
|
||||
var token Token
|
||||
json.Unmarshal([]byte(MockTokenJSON), &token)
|
||||
return &token
|
||||
}
|
||||
|
||||
func TestSaveToken(t *testing.T) {
|
||||
f, err := ioutil.TempFile("", "testloadtoken")
|
||||
if err != nil {
|
||||
t.Fatalf("azure: unexpected error when creating temp file: %v", err)
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
f.Close()
|
||||
|
||||
mode := os.ModePerm & 0642
|
||||
err = SaveToken(f.Name(), mode, *token())
|
||||
if err != nil {
|
||||
t.Fatalf("azure: unexpected error saving token to file: %v", err)
|
||||
}
|
||||
fi, err := os.Stat(f.Name()) // open a new stat as held ones are not fresh
|
||||
if err != nil {
|
||||
t.Fatalf("azure: stat failed: %v", err)
|
||||
}
|
||||
if runtime.GOOS != "windows" { // permissions don't work on Windows
|
||||
if perm := fi.Mode().Perm(); perm != mode {
|
||||
t.Fatalf("azure: wrong file perm. got:%s; expected:%s file :%s", perm, mode, f.Name())
|
||||
}
|
||||
}
|
||||
|
||||
var actualToken Token
|
||||
var expectedToken Token
|
||||
|
||||
json.Unmarshal([]byte(MockTokenJSON), expectedToken)
|
||||
|
||||
contents, err := ioutil.ReadFile(f.Name())
|
||||
if err != nil {
|
||||
t.Fatal("!!")
|
||||
}
|
||||
json.Unmarshal(contents, actualToken)
|
||||
|
||||
if !reflect.DeepEqual(actualToken, expectedToken) {
|
||||
t.Fatal("azure: token was not serialized correctly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveTokenFailsNoPermission(t *testing.T) {
|
||||
pathWhereWeShouldntHavePermission := "/usr/thiswontwork/atall"
|
||||
if runtime.GOOS == "windows" {
|
||||
pathWhereWeShouldntHavePermission = path.Join(os.Getenv("windir"), "system32\\mytokendir\\mytoken")
|
||||
}
|
||||
err := SaveToken(pathWhereWeShouldntHavePermission, 0644, *token())
|
||||
expectedSubstring := "failed to create directory"
|
||||
if err == nil || !strings.Contains(err.Error(), expectedSubstring) {
|
||||
t.Fatalf("azure: failed to get correct error expected(%s) actual(%v)", expectedSubstring, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveTokenFailsCantCreate(t *testing.T) {
|
||||
tokenPath := "/thiswontwork"
|
||||
if runtime.GOOS == "windows" {
|
||||
tokenPath = path.Join(os.Getenv("windir"), "system32")
|
||||
}
|
||||
err := SaveToken(tokenPath, 0644, *token())
|
||||
expectedSubstring := "failed to create the temp file to write the token"
|
||||
if err == nil || !strings.Contains(err.Error(), expectedSubstring) {
|
||||
t.Fatalf("azure: failed to get correct error expected(%s) actual(%v)", expectedSubstring, err)
|
||||
}
|
||||
}
|
||||
261
vendor/github.com/Azure/go-autorest/autorest/adal/token.go
generated
vendored
261
vendor/github.com/Azure/go-autorest/autorest/adal/token.go
generated
vendored
|
|
@ -27,6 +27,7 @@ import (
|
|||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/date"
|
||||
|
|
@ -42,9 +43,15 @@ const (
|
|||
// OAuthGrantTypeClientCredentials is the "grant_type" identifier used in credential flows
|
||||
OAuthGrantTypeClientCredentials = "client_credentials"
|
||||
|
||||
// OAuthGrantTypeUserPass is the "grant_type" identifier used in username and password auth flows
|
||||
OAuthGrantTypeUserPass = "password"
|
||||
|
||||
// OAuthGrantTypeRefreshToken is the "grant_type" identifier used in refresh token flows
|
||||
OAuthGrantTypeRefreshToken = "refresh_token"
|
||||
|
||||
// OAuthGrantTypeAuthorizationCode is the "grant_type" identifier used in authorization code flows
|
||||
OAuthGrantTypeAuthorizationCode = "authorization_code"
|
||||
|
||||
// metadataHeader is the header required by MSI extension
|
||||
metadataHeader = "Metadata"
|
||||
)
|
||||
|
|
@ -54,6 +61,12 @@ type OAuthTokenProvider interface {
|
|||
OAuthToken() string
|
||||
}
|
||||
|
||||
// TokenRefreshError is an interface used by errors returned during token refresh.
|
||||
type TokenRefreshError interface {
|
||||
error
|
||||
Response() *http.Response
|
||||
}
|
||||
|
||||
// Refresher is an interface for token refresh functionality
|
||||
type Refresher interface {
|
||||
Refresh() error
|
||||
|
|
@ -78,6 +91,11 @@ type Token struct {
|
|||
Type string `json:"token_type"`
|
||||
}
|
||||
|
||||
// IsZero returns true if the token object is zero-initialized.
|
||||
func (t Token) IsZero() bool {
|
||||
return t == Token{}
|
||||
}
|
||||
|
||||
// Expires returns the time.Time when the Token expires.
|
||||
func (t Token) Expires() time.Time {
|
||||
s, err := strconv.Atoi(t.ExpiresOn)
|
||||
|
|
@ -145,6 +163,34 @@ type ServicePrincipalCertificateSecret struct {
|
|||
type ServicePrincipalMSISecret struct {
|
||||
}
|
||||
|
||||
// ServicePrincipalUsernamePasswordSecret implements ServicePrincipalSecret for username and password auth.
|
||||
type ServicePrincipalUsernamePasswordSecret struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// ServicePrincipalAuthorizationCodeSecret implements ServicePrincipalSecret for authorization code auth.
|
||||
type ServicePrincipalAuthorizationCodeSecret struct {
|
||||
ClientSecret string
|
||||
AuthorizationCode string
|
||||
RedirectURI string
|
||||
}
|
||||
|
||||
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||
func (secret *ServicePrincipalAuthorizationCodeSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||
v.Set("code", secret.AuthorizationCode)
|
||||
v.Set("client_secret", secret.ClientSecret)
|
||||
v.Set("redirect_uri", secret.RedirectURI)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||
func (secret *ServicePrincipalUsernamePasswordSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||
v.Set("username", secret.Username)
|
||||
v.Set("password", secret.Password)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||
func (msiSecret *ServicePrincipalMSISecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||
return nil
|
||||
|
|
@ -199,25 +245,46 @@ func (secret *ServicePrincipalCertificateSecret) SetAuthenticationValues(spt *Se
|
|||
type ServicePrincipalToken struct {
|
||||
Token
|
||||
|
||||
secret ServicePrincipalSecret
|
||||
oauthConfig OAuthConfig
|
||||
clientID string
|
||||
resource string
|
||||
autoRefresh bool
|
||||
refreshWithin time.Duration
|
||||
sender Sender
|
||||
secret ServicePrincipalSecret
|
||||
oauthConfig OAuthConfig
|
||||
clientID string
|
||||
resource string
|
||||
autoRefresh bool
|
||||
autoRefreshLock *sync.Mutex
|
||||
refreshWithin time.Duration
|
||||
sender Sender
|
||||
|
||||
refreshCallbacks []TokenRefreshCallback
|
||||
}
|
||||
|
||||
func validateOAuthConfig(oac OAuthConfig) error {
|
||||
if oac.IsZero() {
|
||||
return fmt.Errorf("parameter 'oauthConfig' cannot be zero-initialized")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewServicePrincipalTokenWithSecret create a ServicePrincipalToken using the supplied ServicePrincipalSecret implementation.
|
||||
func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, resource string, secret ServicePrincipalSecret, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(id, "id"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(resource, "resource"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil {
|
||||
return nil, fmt.Errorf("parameter 'secret' cannot be nil")
|
||||
}
|
||||
spt := &ServicePrincipalToken{
|
||||
oauthConfig: oauthConfig,
|
||||
secret: secret,
|
||||
clientID: id,
|
||||
resource: resource,
|
||||
autoRefresh: true,
|
||||
autoRefreshLock: &sync.Mutex{},
|
||||
refreshWithin: defaultRefresh,
|
||||
sender: &http.Client{},
|
||||
refreshCallbacks: callbacks,
|
||||
|
|
@ -227,6 +294,18 @@ func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, reso
|
|||
|
||||
// NewServicePrincipalTokenFromManualToken creates a ServicePrincipalToken using the supplied token
|
||||
func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID string, resource string, token Token, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(clientID, "clientID"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(resource, "resource"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if token.IsZero() {
|
||||
return nil, fmt.Errorf("parameter 'token' cannot be zero-initialized")
|
||||
}
|
||||
spt, err := NewServicePrincipalTokenWithSecret(
|
||||
oauthConfig,
|
||||
clientID,
|
||||
|
|
@ -245,6 +324,18 @@ func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID s
|
|||
// NewServicePrincipalToken creates a ServicePrincipalToken from the supplied Service Principal
|
||||
// credentials scoped to the named resource.
|
||||
func NewServicePrincipalToken(oauthConfig OAuthConfig, clientID string, secret string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(clientID, "clientID"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(secret, "secret"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(resource, "resource"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewServicePrincipalTokenWithSecret(
|
||||
oauthConfig,
|
||||
clientID,
|
||||
|
|
@ -256,8 +347,23 @@ func NewServicePrincipalToken(oauthConfig OAuthConfig, clientID string, secret s
|
|||
)
|
||||
}
|
||||
|
||||
// NewServicePrincipalTokenFromCertificate create a ServicePrincipalToken from the supplied pkcs12 bytes.
|
||||
// NewServicePrincipalTokenFromCertificate creates a ServicePrincipalToken from the supplied pkcs12 bytes.
|
||||
func NewServicePrincipalTokenFromCertificate(oauthConfig OAuthConfig, clientID string, certificate *x509.Certificate, privateKey *rsa.PrivateKey, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(clientID, "clientID"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(resource, "resource"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if certificate == nil {
|
||||
return nil, fmt.Errorf("parameter 'certificate' cannot be nil")
|
||||
}
|
||||
if privateKey == nil {
|
||||
return nil, fmt.Errorf("parameter 'privateKey' cannot be nil")
|
||||
}
|
||||
return NewServicePrincipalTokenWithSecret(
|
||||
oauthConfig,
|
||||
clientID,
|
||||
|
|
@ -270,6 +376,70 @@ func NewServicePrincipalTokenFromCertificate(oauthConfig OAuthConfig, clientID s
|
|||
)
|
||||
}
|
||||
|
||||
// NewServicePrincipalTokenFromUsernamePassword creates a ServicePrincipalToken from the username and password.
|
||||
func NewServicePrincipalTokenFromUsernamePassword(oauthConfig OAuthConfig, clientID string, username string, password string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(clientID, "clientID"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(username, "username"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(password, "password"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(resource, "resource"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewServicePrincipalTokenWithSecret(
|
||||
oauthConfig,
|
||||
clientID,
|
||||
resource,
|
||||
&ServicePrincipalUsernamePasswordSecret{
|
||||
Username: username,
|
||||
Password: password,
|
||||
},
|
||||
callbacks...,
|
||||
)
|
||||
}
|
||||
|
||||
// NewServicePrincipalTokenFromAuthorizationCode creates a ServicePrincipalToken from the
|
||||
func NewServicePrincipalTokenFromAuthorizationCode(oauthConfig OAuthConfig, clientID string, clientSecret string, authorizationCode string, redirectURI string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
|
||||
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(clientID, "clientID"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(clientSecret, "clientSecret"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(authorizationCode, "authorizationCode"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(redirectURI, "redirectURI"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(resource, "resource"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewServicePrincipalTokenWithSecret(
|
||||
oauthConfig,
|
||||
clientID,
|
||||
resource,
|
||||
&ServicePrincipalAuthorizationCodeSecret{
|
||||
ClientSecret: clientSecret,
|
||||
AuthorizationCode: authorizationCode,
|
||||
RedirectURI: redirectURI,
|
||||
},
|
||||
callbacks...,
|
||||
)
|
||||
}
|
||||
|
||||
// GetMSIVMEndpoint gets the MSI endpoint on Virtual Machines.
|
||||
func GetMSIVMEndpoint() (string, error) {
|
||||
return getMSIVMEndpoint(msiPath)
|
||||
|
|
@ -293,7 +463,29 @@ func getMSIVMEndpoint(path string) (string, error) {
|
|||
}
|
||||
|
||||
// NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension.
|
||||
// It will use the system assigned identity when creating the token.
|
||||
func NewServicePrincipalTokenFromMSI(msiEndpoint, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, nil, callbacks...)
|
||||
}
|
||||
|
||||
// NewServicePrincipalTokenFromMSIWithUserAssignedID creates a ServicePrincipalToken via the MSI VM Extension.
|
||||
// It will use the specified user assigned identity when creating the token.
|
||||
func NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint, resource string, userAssignedID string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, &userAssignedID, callbacks...)
|
||||
}
|
||||
|
||||
func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedID *string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
if err := validateStringParam(msiEndpoint, "msiEndpoint"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateStringParam(resource, "resource"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userAssignedID != nil {
|
||||
if err := validateStringParam(*userAssignedID, "userAssignedID"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// We set the oauth config token endpoint to be MSI's endpoint
|
||||
msiEndpointURL, err := url.Parse(msiEndpoint)
|
||||
if err != nil {
|
||||
|
|
@ -310,19 +502,49 @@ func NewServicePrincipalTokenFromMSI(msiEndpoint, resource string, callbacks ...
|
|||
secret: &ServicePrincipalMSISecret{},
|
||||
resource: resource,
|
||||
autoRefresh: true,
|
||||
autoRefreshLock: &sync.Mutex{},
|
||||
refreshWithin: defaultRefresh,
|
||||
sender: &http.Client{},
|
||||
refreshCallbacks: callbacks,
|
||||
}
|
||||
|
||||
if userAssignedID != nil {
|
||||
spt.clientID = *userAssignedID
|
||||
}
|
||||
|
||||
return spt, nil
|
||||
}
|
||||
|
||||
// internal type that implements TokenRefreshError
|
||||
type tokenRefreshError struct {
|
||||
message string
|
||||
resp *http.Response
|
||||
}
|
||||
|
||||
// Error implements the error interface which is part of the TokenRefreshError interface.
|
||||
func (tre tokenRefreshError) Error() string {
|
||||
return tre.message
|
||||
}
|
||||
|
||||
// Response implements the TokenRefreshError interface, it returns the raw HTTP response from the refresh operation.
|
||||
func (tre tokenRefreshError) Response() *http.Response {
|
||||
return tre.resp
|
||||
}
|
||||
|
||||
func newTokenRefreshError(message string, resp *http.Response) TokenRefreshError {
|
||||
return tokenRefreshError{message: message, resp: resp}
|
||||
}
|
||||
|
||||
// EnsureFresh will refresh the token if it will expire within the refresh window (as set by
|
||||
// RefreshWithin) and autoRefresh flag is on.
|
||||
// RefreshWithin) and autoRefresh flag is on. This method is safe for concurrent use.
|
||||
func (spt *ServicePrincipalToken) EnsureFresh() error {
|
||||
if spt.autoRefresh && spt.WillExpireIn(spt.refreshWithin) {
|
||||
return spt.Refresh()
|
||||
// take the lock then check to see if the token was already refreshed
|
||||
spt.autoRefreshLock.Lock()
|
||||
defer spt.autoRefreshLock.Unlock()
|
||||
if spt.WillExpireIn(spt.refreshWithin) {
|
||||
return spt.Refresh()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -341,15 +563,28 @@ func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error {
|
|||
}
|
||||
|
||||
// Refresh obtains a fresh token for the Service Principal.
|
||||
// This method is not safe for concurrent use and should be syncrhonized.
|
||||
func (spt *ServicePrincipalToken) Refresh() error {
|
||||
return spt.refreshInternal(spt.resource)
|
||||
}
|
||||
|
||||
// RefreshExchange refreshes the token, but for a different resource.
|
||||
// This method is not safe for concurrent use and should be syncrhonized.
|
||||
func (spt *ServicePrincipalToken) RefreshExchange(resource string) error {
|
||||
return spt.refreshInternal(resource)
|
||||
}
|
||||
|
||||
func (spt *ServicePrincipalToken) getGrantType() string {
|
||||
switch spt.secret.(type) {
|
||||
case *ServicePrincipalUsernamePasswordSecret:
|
||||
return OAuthGrantTypeUserPass
|
||||
case *ServicePrincipalAuthorizationCodeSecret:
|
||||
return OAuthGrantTypeAuthorizationCode
|
||||
default:
|
||||
return OAuthGrantTypeClientCredentials
|
||||
}
|
||||
}
|
||||
|
||||
func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
|
||||
v := url.Values{}
|
||||
v.Set("client_id", spt.clientID)
|
||||
|
|
@ -359,7 +594,7 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
|
|||
v.Set("grant_type", OAuthGrantTypeRefreshToken)
|
||||
v.Set("refresh_token", spt.RefreshToken)
|
||||
} else {
|
||||
v.Set("grant_type", OAuthGrantTypeClientCredentials)
|
||||
v.Set("grant_type", spt.getGrantType())
|
||||
err := spt.secret.SetAuthenticationValues(spt, &v)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -388,9 +623,9 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
|
|||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if err != nil {
|
||||
return fmt.Errorf("adal: Refresh request failed. Status Code = '%d'. Failed reading response body", resp.StatusCode)
|
||||
return newTokenRefreshError(fmt.Sprintf("adal: Refresh request failed. Status Code = '%d'. Failed reading response body", resp.StatusCode), resp)
|
||||
}
|
||||
return fmt.Errorf("adal: Refresh request failed. Status Code = '%d'. Response body: %s", resp.StatusCode, string(rb))
|
||||
return newTokenRefreshError(fmt.Sprintf("adal: Refresh request failed. Status Code = '%d'. Response body: %s", resp.StatusCode, string(rb)), resp)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
654
vendor/github.com/Azure/go-autorest/autorest/adal/token_test.go
generated
vendored
654
vendor/github.com/Azure/go-autorest/autorest/adal/token_test.go
generated
vendored
|
|
@ -1,654 +0,0 @@
|
|||
package adal
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/date"
|
||||
"github.com/Azure/go-autorest/autorest/mocks"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultFormData = "client_id=id&client_secret=secret&grant_type=client_credentials&resource=resource"
|
||||
defaultManualFormData = "client_id=id&grant_type=refresh_token&refresh_token=refreshtoken&resource=resource"
|
||||
)
|
||||
|
||||
func TestTokenExpires(t *testing.T) {
|
||||
tt := time.Now().Add(5 * time.Second)
|
||||
tk := newTokenExpiresAt(tt)
|
||||
|
||||
if tk.Expires().Equal(tt) {
|
||||
t.Fatalf("adal: Token#Expires miscalculated expiration time -- received %v, expected %v", tk.Expires(), tt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenIsExpired(t *testing.T) {
|
||||
tk := newTokenExpiresAt(time.Now().Add(-5 * time.Second))
|
||||
|
||||
if !tk.IsExpired() {
|
||||
t.Fatalf("adal: Token#IsExpired failed to mark a stale token as expired -- now %v, token expires at %v",
|
||||
time.Now().UTC(), tk.Expires())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenIsExpiredUninitialized(t *testing.T) {
|
||||
tk := &Token{}
|
||||
|
||||
if !tk.IsExpired() {
|
||||
t.Fatalf("adal: An uninitialized Token failed to mark itself as expired (expiration time %v)", tk.Expires())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenIsNoExpired(t *testing.T) {
|
||||
tk := newTokenExpiresAt(time.Now().Add(1000 * time.Second))
|
||||
|
||||
if tk.IsExpired() {
|
||||
t.Fatalf("adal: Token marked a fresh token as expired -- now %v, token expires at %v", time.Now().UTC(), tk.Expires())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenWillExpireIn(t *testing.T) {
|
||||
d := 5 * time.Second
|
||||
tk := newTokenExpiresIn(d)
|
||||
|
||||
if !tk.WillExpireIn(d) {
|
||||
t.Fatal("adal: Token#WillExpireIn mismeasured expiration time")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenSetAutoRefresh(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
if !spt.autoRefresh {
|
||||
t.Fatal("adal: ServicePrincipalToken did not default to automatic token refreshing")
|
||||
}
|
||||
|
||||
spt.SetAutoRefresh(false)
|
||||
if spt.autoRefresh {
|
||||
t.Fatal("adal: ServicePrincipalToken#SetAutoRefresh did not disable automatic token refreshing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenSetRefreshWithin(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
if spt.refreshWithin != defaultRefresh {
|
||||
t.Fatal("adal: ServicePrincipalToken did not correctly set the default refresh interval")
|
||||
}
|
||||
|
||||
spt.SetRefreshWithin(2 * defaultRefresh)
|
||||
if spt.refreshWithin != 2*defaultRefresh {
|
||||
t.Fatal("adal: ServicePrincipalToken#SetRefreshWithin did not set the refresh interval")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenSetSender(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
c := &http.Client{}
|
||||
spt.SetSender(c)
|
||||
if !reflect.DeepEqual(c, spt.sender) {
|
||||
t.Fatal("adal: ServicePrincipalToken#SetSender did not set the sender")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshUsesPOST(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method != "POST" {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set HTTP method -- expected %v, received %v", "POST", r.Method)
|
||||
}
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("the response was not closed!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenFromMSIRefreshUsesPOST(t *testing.T) {
|
||||
resource := "https://resource"
|
||||
cb := func(token Token) error { return nil }
|
||||
|
||||
spt, err := NewServicePrincipalTokenFromMSI("http://msiendpoint/", resource, cb)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get MSI SPT: %v", err)
|
||||
}
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method != "POST" {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set HTTP method -- expected %v, received %v", "POST", r.Method)
|
||||
}
|
||||
if h := r.Header.Get("Metadata"); h != "true" {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set Metadata header for MSI")
|
||||
}
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err = spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
|
||||
if body.IsOpen() {
|
||||
t.Fatalf("the response was not closed!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshSetsMimeType(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Header.Get(http.CanonicalHeaderKey("Content-Type")) != "application/x-www-form-urlencoded" {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set Content-Type -- expected %v, received %v",
|
||||
"application/x-form-urlencoded",
|
||||
r.Header.Get(http.CanonicalHeaderKey("Content-Type")))
|
||||
}
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshSetsURL(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.String() != TestOAuthConfig.TokenEndpoint.String() {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set the URL -- expected %v, received %v",
|
||||
TestOAuthConfig.TokenEndpoint, r.URL)
|
||||
}
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testServicePrincipalTokenRefreshSetsBody(t *testing.T, spt *ServicePrincipalToken, f func(*testing.T, []byte)) {
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("adal: Failed to read body of Service Principal token request (%v)", err)
|
||||
}
|
||||
f(t, b)
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenManualRefreshSetsBody(t *testing.T) {
|
||||
sptManual := newServicePrincipalTokenManual()
|
||||
testServicePrincipalTokenRefreshSetsBody(t, sptManual, func(t *testing.T, b []byte) {
|
||||
if string(b) != defaultManualFormData {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set the HTTP Request Body -- expected %v, received %v",
|
||||
defaultManualFormData, string(b))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenCertficateRefreshSetsBody(t *testing.T) {
|
||||
sptCert := newServicePrincipalTokenCertificate(t)
|
||||
testServicePrincipalTokenRefreshSetsBody(t, sptCert, func(t *testing.T, b []byte) {
|
||||
body := string(b)
|
||||
|
||||
values, _ := url.ParseQuery(body)
|
||||
if values["client_assertion_type"][0] != "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" ||
|
||||
values["client_id"][0] != "id" ||
|
||||
values["grant_type"][0] != "client_credentials" ||
|
||||
values["resource"][0] != "resource" {
|
||||
t.Fatalf("adal: ServicePrincipalTokenCertificate#Refresh did not correctly set the HTTP Request Body.")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenSecretRefreshSetsBody(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
testServicePrincipalTokenRefreshSetsBody(t, spt, func(t *testing.T, b []byte) {
|
||||
if string(b) != defaultFormData {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set the HTTP Request Body -- expected %v, received %v",
|
||||
defaultFormData, string(b))
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshClosesRequestBody(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
if resp.Body.(*mocks.Body).IsOpen() {
|
||||
t.Fatal("adal: ServicePrincipalToken#Refresh failed to close the HTTP Response Body")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshRejectsResponsesWithStatusNotOK(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusUnauthorized, "Unauthorized")
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err == nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh should reject a response with status != %d", http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshRejectsEmptyBody(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
return mocks.NewResponse(), nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.Refresh()
|
||||
if err == nil {
|
||||
t.Fatal("adal: ServicePrincipalToken#Refresh should reject an empty token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshPropagatesErrors(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
c := mocks.NewSender()
|
||||
c.SetError(fmt.Errorf("Faux Error"))
|
||||
spt.SetSender(c)
|
||||
|
||||
err := spt.Refresh()
|
||||
if err == nil {
|
||||
t.Fatal("adal: Failed to propagate the request error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshReturnsErrorIfNotOk(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
c := mocks.NewSender()
|
||||
c.AppendResponse(mocks.NewResponseWithStatus("401 NotAuthorized", http.StatusUnauthorized))
|
||||
spt.SetSender(c)
|
||||
|
||||
err := spt.Refresh()
|
||||
if err == nil {
|
||||
t.Fatalf("adal: Failed to return an when receiving a status code other than HTTP %d", http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenRefreshUnmarshals(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
|
||||
expiresOn := strconv.Itoa(int(time.Now().Add(3600 * time.Second).Sub(date.UnixEpoch()).Seconds()))
|
||||
j := newTokenJSON(expiresOn, "resource")
|
||||
resp := mocks.NewResponseWithContent(j)
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
} else if spt.AccessToken != "accessToken" ||
|
||||
spt.ExpiresIn != "3600" ||
|
||||
spt.ExpiresOn != expiresOn ||
|
||||
spt.NotBefore != expiresOn ||
|
||||
spt.Resource != "resource" ||
|
||||
spt.Type != "Bearer" {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh failed correctly unmarshal the JSON -- expected %v, received %v",
|
||||
j, *spt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenEnsureFreshRefreshes(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
expireToken(&spt.Token)
|
||||
|
||||
body := mocks.NewBody(newTokenJSON("test", "test"))
|
||||
resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")
|
||||
|
||||
f := false
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
f = true
|
||||
return resp, nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.EnsureFresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#EnsureFresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
if !f {
|
||||
t.Fatal("adal: ServicePrincipalToken#EnsureFresh failed to call Refresh for stale token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServicePrincipalTokenEnsureFreshSkipsIfFresh(t *testing.T) {
|
||||
spt := newServicePrincipalToken()
|
||||
setTokenToExpireIn(&spt.Token, 1000*time.Second)
|
||||
|
||||
f := false
|
||||
c := mocks.NewSender()
|
||||
s := DecorateSender(c,
|
||||
(func() SendDecorator {
|
||||
return func(s Sender) Sender {
|
||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||
f = true
|
||||
return mocks.NewResponse(), nil
|
||||
})
|
||||
}
|
||||
})())
|
||||
spt.SetSender(s)
|
||||
err := spt.EnsureFresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#EnsureFresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
if f {
|
||||
t.Fatal("adal: ServicePrincipalToken#EnsureFresh invoked Refresh for fresh token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshCallback(t *testing.T) {
|
||||
callbackTriggered := false
|
||||
spt := newServicePrincipalToken(func(Token) error {
|
||||
callbackTriggered = true
|
||||
return nil
|
||||
})
|
||||
|
||||
expiresOn := strconv.Itoa(int(time.Now().Add(3600 * time.Second).Sub(date.UnixEpoch()).Seconds()))
|
||||
|
||||
sender := mocks.NewSender()
|
||||
j := newTokenJSON(expiresOn, "resource")
|
||||
sender.AppendResponse(mocks.NewResponseWithContent(j))
|
||||
spt.SetSender(sender)
|
||||
err := spt.Refresh()
|
||||
if err != nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err)
|
||||
}
|
||||
if !callbackTriggered {
|
||||
t.Fatalf("adal: RefreshCallback failed to trigger call callback")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshCallbackErrorPropagates(t *testing.T) {
|
||||
errorText := "this is an error text"
|
||||
spt := newServicePrincipalToken(func(Token) error {
|
||||
return fmt.Errorf(errorText)
|
||||
})
|
||||
|
||||
expiresOn := strconv.Itoa(int(time.Now().Add(3600 * time.Second).Sub(date.UnixEpoch()).Seconds()))
|
||||
|
||||
sender := mocks.NewSender()
|
||||
j := newTokenJSON(expiresOn, "resource")
|
||||
sender.AppendResponse(mocks.NewResponseWithContent(j))
|
||||
spt.SetSender(sender)
|
||||
err := spt.Refresh()
|
||||
|
||||
if err == nil || !strings.Contains(err.Error(), errorText) {
|
||||
t.Fatalf("adal: RefreshCallback failed to propagate error")
|
||||
}
|
||||
}
|
||||
|
||||
// This demonstrates the danger of manual token without a refresh token
|
||||
func TestServicePrincipalTokenManualRefreshFailsWithoutRefresh(t *testing.T) {
|
||||
spt := newServicePrincipalTokenManual()
|
||||
spt.RefreshToken = ""
|
||||
err := spt.Refresh()
|
||||
if err == nil {
|
||||
t.Fatalf("adal: ServicePrincipalToken#Refresh should have failed with a ManualTokenSecret without a refresh token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewServicePrincipalTokenFromMSI(t *testing.T) {
|
||||
resource := "https://resource"
|
||||
cb := func(token Token) error { return nil }
|
||||
|
||||
spt, err := NewServicePrincipalTokenFromMSI("http://msiendpoint/", resource, cb)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get MSI SPT: %v", err)
|
||||
}
|
||||
|
||||
// check some of the SPT fields
|
||||
if _, ok := spt.secret.(*ServicePrincipalMSISecret); !ok {
|
||||
t.Fatal("SPT secret was not of MSI type")
|
||||
}
|
||||
|
||||
if spt.resource != resource {
|
||||
t.Fatal("SPT came back with incorrect resource")
|
||||
}
|
||||
|
||||
if len(spt.refreshCallbacks) != 1 {
|
||||
t.Fatal("SPT had incorrect refresh callbacks.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetVMEndpoint(t *testing.T) {
|
||||
tempSettingsFile, err := ioutil.TempFile("", "ManagedIdentity-Settings")
|
||||
if err != nil {
|
||||
t.Fatal("Couldn't write temp settings file")
|
||||
}
|
||||
defer os.Remove(tempSettingsFile.Name())
|
||||
|
||||
settingsContents := []byte(`{
|
||||
"url": "http://msiendpoint/"
|
||||
}`)
|
||||
|
||||
if _, err := tempSettingsFile.Write(settingsContents); err != nil {
|
||||
t.Fatal("Couldn't fill temp settings file")
|
||||
}
|
||||
|
||||
endpoint, err := getMSIVMEndpoint(tempSettingsFile.Name())
|
||||
if err != nil {
|
||||
t.Fatal("Coudn't get VM endpoint")
|
||||
}
|
||||
|
||||
if endpoint != "http://msiendpoint/" {
|
||||
t.Fatal("Didn't get correct endpoint")
|
||||
}
|
||||
}
|
||||
|
||||
func newToken() *Token {
|
||||
return &Token{
|
||||
AccessToken: "ASECRETVALUE",
|
||||
Resource: "https://azure.microsoft.com/",
|
||||
Type: "Bearer",
|
||||
}
|
||||
}
|
||||
|
||||
func newTokenJSON(expiresOn string, resource string) string {
|
||||
return fmt.Sprintf(`{
|
||||
"access_token" : "accessToken",
|
||||
"expires_in" : "3600",
|
||||
"expires_on" : "%s",
|
||||
"not_before" : "%s",
|
||||
"resource" : "%s",
|
||||
"token_type" : "Bearer"
|
||||
}`,
|
||||
expiresOn, expiresOn, resource)
|
||||
}
|
||||
|
||||
func newTokenExpiresIn(expireIn time.Duration) *Token {
|
||||
return setTokenToExpireIn(newToken(), expireIn)
|
||||
}
|
||||
|
||||
func newTokenExpiresAt(expireAt time.Time) *Token {
|
||||
return setTokenToExpireAt(newToken(), expireAt)
|
||||
}
|
||||
|
||||
func expireToken(t *Token) *Token {
|
||||
return setTokenToExpireIn(t, 0)
|
||||
}
|
||||
|
||||
func setTokenToExpireAt(t *Token, expireAt time.Time) *Token {
|
||||
t.ExpiresIn = "3600"
|
||||
t.ExpiresOn = strconv.Itoa(int(expireAt.Sub(date.UnixEpoch()).Seconds()))
|
||||
t.NotBefore = t.ExpiresOn
|
||||
return t
|
||||
}
|
||||
|
||||
func setTokenToExpireIn(t *Token, expireIn time.Duration) *Token {
|
||||
return setTokenToExpireAt(t, time.Now().Add(expireIn))
|
||||
}
|
||||
|
||||
func newServicePrincipalToken(callbacks ...TokenRefreshCallback) *ServicePrincipalToken {
|
||||
spt, _ := NewServicePrincipalToken(TestOAuthConfig, "id", "secret", "resource", callbacks...)
|
||||
return spt
|
||||
}
|
||||
|
||||
func newServicePrincipalTokenManual() *ServicePrincipalToken {
|
||||
token := newToken()
|
||||
token.RefreshToken = "refreshtoken"
|
||||
spt, _ := NewServicePrincipalTokenFromManualToken(TestOAuthConfig, "id", "resource", *token)
|
||||
return spt
|
||||
}
|
||||
|
||||
func newServicePrincipalTokenCertificate(t *testing.T) *ServicePrincipalToken {
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(0),
|
||||
Subject: pkix.Name{CommonName: "test"},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
certificateBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
certificate, err := x509.ParseCertificate(certificateBytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
spt, _ := NewServicePrincipalTokenFromCertificate(TestOAuthConfig, "id", certificate, privateKey, "resource")
|
||||
return spt
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue