Skip to content

Commit 81c4f03

Browse files
authored
Bearer token authentication requires TLS (Azure#21673)
1 parent 6bb9bb9 commit 81c4f03

File tree

6 files changed

+58
-14
lines changed

6 files changed

+58
-14
lines changed

sdk/azcore/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
### Bugs Fixed
1515

1616
* Fixed an issue that could cause some ARM RPs to not be automatically registered.
17+
* Block bearer token authentication for non TLS protected endpoints.
1718

1819
### Other Changes
1920

sdk/azcore/arm/runtime/pipeline_test.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@ import (
2727

2828
func TestNewPipelineWithAPIVersion(t *testing.T) {
2929
version := "42"
30-
srv, close := mock.NewServer()
30+
srv, close := mock.NewTLSServer()
3131
defer close()
3232
srv.SetResponse()
3333
pl, err := NewPipeline("...", "...", mockCredential{}, azruntime.PipelineOptions{}, &armpolicy.ClientOptions{
3434
ClientOptions: policy.ClientOptions{
3535
APIVersion: version,
36+
Transport: srv,
3637
},
3738
})
3839
require.NoError(t, err)
@@ -44,7 +45,7 @@ func TestNewPipelineWithAPIVersion(t *testing.T) {
4445
}
4546

4647
func TestNewPipelineWithOptions(t *testing.T) {
47-
srv, close := mock.NewServer()
48+
srv, close := mock.NewTLSServer()
4849
defer close()
4950
srv.AppendResponse()
5051
opt := armpolicy.ClientOptions{}
@@ -71,7 +72,7 @@ func TestNewPipelineWithOptions(t *testing.T) {
7172

7273
func TestNewPipelineWithCustomTelemetry(t *testing.T) {
7374
const myTelemetry = "something"
74-
srv, close := mock.NewServer()
75+
srv, close := mock.NewTLSServer()
7576
defer close()
7677
srv.AppendResponse()
7778
opt := armpolicy.ClientOptions{}
@@ -101,7 +102,7 @@ func TestNewPipelineWithCustomTelemetry(t *testing.T) {
101102
}
102103

103104
func TestDisableAutoRPRegistration(t *testing.T) {
104-
srv, close := mock.NewServer()
105+
srv, close := mock.NewTLSServer()
105106
defer close()
106107
// initial response that RP is unregistered
107108
srv.SetResponse(mock.WithStatusCode(http.StatusConflict), mock.WithBody([]byte(rpUnregisteredResp1)))
@@ -148,7 +149,7 @@ func (p *countingPolicy) Do(req *policy.Request) (*http.Response, error) {
148149
}
149150

150151
func TestPipelineWithCustomPolicies(t *testing.T) {
151-
srv, close := mock.NewServer()
152+
srv, close := mock.NewTLSServer()
152153
defer close()
153154
// initial response is a failure to trigger retry
154155
srv.AppendResponse(mock.WithStatusCode(http.StatusInternalServerError))
@@ -189,7 +190,7 @@ func TestPipelineWithCustomPolicies(t *testing.T) {
189190

190191
func TestPipelineAudience(t *testing.T) {
191192
for _, c := range []cloud.Configuration{cloud.AzureChina, cloud.AzureGovernment, cloud.AzurePublic} {
192-
srv, close := mock.NewServer()
193+
srv, close := mock.NewTLSServer()
193194
defer close()
194195
srv.AppendResponse(mock.WithStatusCode(200))
195196
opts := &armpolicy.ClientOptions{}
@@ -249,11 +250,21 @@ func TestPipelineWithIncompleteCloudConfig(t *testing.T) {
249250
}
250251

251252
func TestPipelineDoConcurrent(t *testing.T) {
252-
srv, close := mock.NewServer()
253+
srv, close := mock.NewTLSServer()
253254
defer close()
254255
srv.SetResponse()
255256

256-
pl, err := NewPipeline("TestPipelineDoConcurrent", shared.Version, mockCredential{}, azruntime.PipelineOptions{}, nil)
257+
pl, err := NewPipeline(
258+
"TestPipelineDoConcurrent",
259+
shared.Version,
260+
mockCredential{},
261+
azruntime.PipelineOptions{},
262+
&armpolicy.ClientOptions{
263+
ClientOptions: policy.ClientOptions{
264+
Transport: srv,
265+
},
266+
},
267+
)
257268
require.NoError(t, err)
258269

259270
plErr := make(chan error, 1)

sdk/azcore/arm/runtime/policy_bearer_token_test.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
1616
armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy"
1717
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
18+
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
1819
azpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
1920
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
2021
"github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo"
@@ -257,7 +258,7 @@ func TestBearerTokenPolicyChallengeParsing(t *testing.T) {
257258
},
258259
} {
259260
t.Run(test.desc, func(t *testing.T) {
260-
srv, close := mock.NewServer()
261+
srv, close := mock.NewTLSServer()
261262
defer close()
262263
srv.SetResponse(mock.WithHeader(shared.HeaderWWWAuthenticate, test.challenge), mock.WithStatusCode(http.StatusUnauthorized))
263264
calls := 0
@@ -286,3 +287,16 @@ func TestBearerTokenPolicyChallengeParsing(t *testing.T) {
286287
})
287288
}
288289
}
290+
291+
func TestBearerTokenPolicyRequiresHTTPS(t *testing.T) {
292+
srv, close := mock.NewServer()
293+
defer close()
294+
b := NewBearerTokenPolicy(mockCredential{}, nil)
295+
pl := newTestPipeline(&policy.ClientOptions{Transport: srv, PerRetryPolicies: []policy.Policy{b}})
296+
req, err := runtime.NewRequest(context.Background(), "GET", srv.URL())
297+
require.NoError(t, err)
298+
_, err = pl.Do(req)
299+
require.Error(t, err)
300+
var nre errorinfo.NonRetriable
301+
require.ErrorAs(t, err, &nre)
302+
}

sdk/azcore/arm/runtime/policy_register_rp_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func testRPRegistrationOptions(srv *mock.Server) *armpolicy.RegistrationOptions
9999
}
100100

101101
func TestRPRegistrationPolicySuccess(t *testing.T) {
102-
srv, close := mock.NewServer()
102+
srv, close := mock.NewTLSServer()
103103
defer close()
104104
// initial response that RP is unregistered
105105
srv.AppendResponse(mock.WithStatusCode(http.StatusConflict), mock.WithBody([]byte(rpUnregisteredResp1)))
@@ -190,7 +190,7 @@ func TestRPRegistrationPolicy409Other(t *testing.T) {
190190
}
191191

192192
func TestRPRegistrationPolicyTimesOut(t *testing.T) {
193-
srv, close := mock.NewServer()
193+
srv, close := mock.NewTLSServer()
194194
defer close()
195195
// initial response that RP is unregistered
196196
srv.AppendResponse(mock.WithStatusCode(http.StatusConflict), mock.WithBody([]byte(rpUnregisteredResp1)))
@@ -220,7 +220,7 @@ func TestRPRegistrationPolicyTimesOut(t *testing.T) {
220220
}
221221

222222
func TestRPRegistrationPolicyExceedsAttempts(t *testing.T) {
223-
srv, close := mock.NewServer()
223+
srv, close := mock.NewTLSServer()
224224
defer close()
225225
// add a cycle of unregistered->registered so that we keep retrying and hit the cap
226226
for i := 0; i < 4; i++ {
@@ -256,7 +256,7 @@ func TestRPRegistrationPolicyExceedsAttempts(t *testing.T) {
256256

257257
// test cancelling registration
258258
func TestRPRegistrationPolicyCanCancel(t *testing.T) {
259-
srv, close := mock.NewServer()
259+
srv, close := mock.NewTLSServer()
260260
defer close()
261261
// initial response that RP is unregistered
262262
srv.AppendResponse(mock.WithStatusCode(http.StatusConflict), mock.WithBody([]byte(rpUnregisteredResp2)))
@@ -325,7 +325,7 @@ func TestRPRegistrationPolicyDisabled(t *testing.T) {
325325
}
326326

327327
func TestRPRegistrationPolicyAudience(t *testing.T) {
328-
srv, close := mock.NewServer()
328+
srv, close := mock.NewTLSServer()
329329
defer close()
330330
// initial response that RP is unregistered
331331
srv.AppendResponse(mock.WithStatusCode(http.StatusConflict), mock.WithBody([]byte(rpUnregisteredResp2)))

sdk/azcore/runtime/policy_bearer_token.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
package runtime
55

66
import (
7+
"errors"
78
"net/http"
9+
"strings"
810
"time"
911

1012
"github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported"
@@ -70,6 +72,9 @@ func (b *BearerTokenPolicy) authenticateAndAuthorize(req *policy.Request) func(p
7072

7173
// Do authorizes a request with a bearer token
7274
func (b *BearerTokenPolicy) Do(req *policy.Request) (*http.Response, error) {
75+
if strings.ToLower(req.Raw().URL.Scheme) != "https" {
76+
return nil, shared.NonRetriableError(errors.New("bearer token authentication is not permitted for non TLS protected (https) endpoints"))
77+
}
7378
var err error
7479
if b.authzHandler.OnRequest != nil {
7580
err = b.authzHandler.OnRequest(req, b.authenticateAndAuthorize(req))

sdk/azcore/runtime/policy_bearer_token_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,3 +224,16 @@ func TestBearerTokenPolicy_AuthZHandlerErrors(t *testing.T) {
224224
require.Equal(t, i+1, srv.Requests())
225225
}
226226
}
227+
228+
func TestBearerTokenPolicy_RequiresHTTPS(t *testing.T) {
229+
srv, close := mock.NewServer()
230+
defer close()
231+
b := NewBearerTokenPolicy(mockCredential{}, nil, nil)
232+
pl := newTestPipeline(&policy.ClientOptions{Transport: srv, PerRetryPolicies: []policy.Policy{b}})
233+
req, err := NewRequest(context.Background(), "GET", srv.URL())
234+
require.NoError(t, err)
235+
_, err = pl.Do(req)
236+
require.Error(t, err)
237+
var nre errorinfo.NonRetriable
238+
require.ErrorAs(t, err, &nre)
239+
}

0 commit comments

Comments
 (0)