diff --git a/src/Authentication.Abstractions/Authentication.Abstractions.csproj b/src/Authentication.Abstractions/Authentication.Abstractions.csproj
index 981ec763eb..340c082292 100644
--- a/src/Authentication.Abstractions/Authentication.Abstractions.csproj
+++ b/src/Authentication.Abstractions/Authentication.Abstractions.csproj
@@ -134,6 +134,7 @@
+
diff --git a/src/Authentication.Abstractions/Interfaces/IRenewableToken.cs b/src/Authentication.Abstractions/Interfaces/IRenewableToken.cs
new file mode 100644
index 0000000000..fa944128c8
--- /dev/null
+++ b/src/Authentication.Abstractions/Interfaces/IRenewableToken.cs
@@ -0,0 +1,26 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright 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.
+// ----------------------------------------------------------------------------------
+
+using System;
+
+namespace Microsoft.Azure.Commands.Common.Authentication
+{
+ ///
+ /// Canonical representation of a renewable access token
+ ///
+ public interface IRenewableToken : IAccessToken
+ {
+ DateTimeOffset ExpiresOn { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Authentication.Test/AuthenticationFactoryTests.cs b/src/Authentication.Test/AuthenticationFactoryTests.cs
index 08941d29f3..c829cf77b7 100644
--- a/src/Authentication.Test/AuthenticationFactoryTests.cs
+++ b/src/Authentication.Test/AuthenticationFactoryTests.cs
@@ -174,9 +174,10 @@ public void CanAuthenticateUsingMSIDefault()
};
AzureSession.Instance.RegisterComponent(HttpClientOperationsFactory.Name, () => TestHttpOperationsFactory.Create(responses, _output), true);
var authFactory = new AuthenticationFactory();
- var token = authFactory.Authenticate(account, environment, tenant, null, null, null);
+ IRenewableToken token = (IRenewableToken) authFactory.Authenticate(account, environment, tenant, null, null, null);
_output.WriteLine($"Received access token for default Uri ${token.AccessToken}");
Assert.Equal(expectedAccessToken, token.AccessToken);
+ Assert.Equal(3600, Math.Round(token.ExpiresOn.DateTime.Subtract(DateTime.UtcNow).TotalSeconds));
var account2 = new AzureAccount
{
Id = userId,
@@ -223,9 +224,10 @@ public void CanAuthenticateUsingMSIResourceId()
};
AzureSession.Instance.RegisterComponent(HttpClientOperationsFactory.Name, () => TestHttpOperationsFactory.Create(responses, _output), true);
var authFactory = new AuthenticationFactory();
- var token = authFactory.Authenticate(account, environment, tenant, null, null, null);
+ IRenewableToken token = (IRenewableToken) authFactory.Authenticate(account, environment, tenant, null, null, null);
_output.WriteLine($"Received access token for default Uri ${token.AccessToken}");
Assert.Equal(expectedAccessToken, token.AccessToken);
+ Assert.Equal(3600, Math.Round(token.ExpiresOn.DateTime.Subtract(DateTime.UtcNow).TotalSeconds));
var account2 = new AzureAccount
{
Id = userId,
@@ -271,9 +273,10 @@ public void CanAuthenticateUsingMSIClientId()
};
AzureSession.Instance.RegisterComponent(HttpClientOperationsFactory.Name, () => TestHttpOperationsFactory.Create(responses, _output), true);
var authFactory = new AuthenticationFactory();
- var token = authFactory.Authenticate(account, environment, tenant, null, null, null);
+ IRenewableToken token = (IRenewableToken) authFactory.Authenticate(account, environment, tenant, null, null, null);
_output.WriteLine($"Received access token for default Uri ${token.AccessToken}");
Assert.Equal(expectedAccessToken, token.AccessToken);
+ Assert.Equal(3600, Math.Round(token.ExpiresOn.DateTime.Subtract(DateTime.UtcNow).TotalSeconds));
var account2 = new AzureAccount
{
Id = userId,
@@ -319,9 +322,10 @@ public void CanAuthenticateUsingMSIObjectId()
};
AzureSession.Instance.RegisterComponent(HttpClientOperationsFactory.Name, () => TestHttpOperationsFactory.Create(responses, _output), true);
var authFactory = new AuthenticationFactory();
- var token = authFactory.Authenticate(account, environment, tenant, null, null, null);
+ IRenewableToken token = (IRenewableToken) authFactory.Authenticate(account, environment, tenant, null, null, null);
_output.WriteLine($"Received access token for default Uri ${token.AccessToken}");
Assert.Equal(expectedAccessToken, token.AccessToken);
+ Assert.Equal(3600, Math.Round(token.ExpiresOn.DateTime.Subtract(DateTime.UtcNow).TotalSeconds));
var account2 = new AzureAccount
{
Id = userId,
diff --git a/src/Authentication/Authentication/ManagedServiceAccessToken.cs b/src/Authentication/Authentication/ManagedServiceAccessToken.cs
index 1cffd8e815..d0fd4ca4e2 100644
--- a/src/Authentication/Authentication/ManagedServiceAccessToken.cs
+++ b/src/Authentication/Authentication/ManagedServiceAccessToken.cs
@@ -23,7 +23,7 @@
namespace Microsoft.Azure.Commands.Common.Authentication
{
- public class ManagedServiceAccessToken : IAccessToken
+ public class ManagedServiceAccessToken : IRenewableToken
{
IAzureAccount _account;
string _tenant;
@@ -104,6 +104,14 @@ public string AccessToken
public string UserId => _account.Id;
+ public DateTimeOffset ExpiresOn
+ {
+ get
+ {
+ return _expiration;
+ }
+ }
+
public void AuthorizeRequest(Action authTokenSetter)
{
authTokenSetter("Bearer", AccessToken);
diff --git a/src/Authentication/Authentication/RawAccessToken.cs b/src/Authentication/Authentication/RawAccessToken.cs
index 9ac1270669..c0a1dda882 100644
--- a/src/Authentication/Authentication/RawAccessToken.cs
+++ b/src/Authentication/Authentication/RawAccessToken.cs
@@ -16,7 +16,7 @@
namespace Microsoft.Azure.Commands.Common.Authentication
{
- public class RawAccessToken : IAccessToken
+ public class RawAccessToken : IRenewableToken
{
public string AccessToken
{
@@ -42,5 +42,7 @@ public void AuthorizeRequest(Action authTokenSetter)
{
authTokenSetter("Bearer", AccessToken);
}
+
+ public DateTimeOffset ExpiresOn { get; set; }
}
}
diff --git a/src/Authentication/Authentication/ServicePrincipalTokenProvider.cs b/src/Authentication/Authentication/ServicePrincipalTokenProvider.cs
index ca3ec6f534..0a7e1522c4 100644
--- a/src/Authentication/Authentication/ServicePrincipalTokenProvider.cs
+++ b/src/Authentication/Authentication/ServicePrincipalTokenProvider.cs
@@ -151,7 +151,7 @@ private void StoreAppKey(string appId, string tenantId, SecureString appKey)
ServicePrincipalKeyStore.SaveKey(appId, tenantId, appKey);
}
- private class ServicePrincipalAccessToken : IAccessToken
+ private class ServicePrincipalAccessToken : IRenewableToken
{
internal readonly AdalConfiguration Configuration;
internal AuthenticationResult AuthResult;
@@ -211,6 +211,8 @@ private bool IsExpired
return timeUntilExpiration < expirationThreshold;
}
}
+
+ public DateTimeOffset ExpiresOn { get { return AuthResult.ExpiresOn; } }
}
}
}
diff --git a/src/Authentication/Authentication/UserTokenProvider.Netcore.cs b/src/Authentication/Authentication/UserTokenProvider.Netcore.cs
index 49f4923170..108a7dbf10 100644
--- a/src/Authentication/Authentication/UserTokenProvider.Netcore.cs
+++ b/src/Authentication/Authentication/UserTokenProvider.Netcore.cs
@@ -238,9 +238,9 @@ private string GetExceptionMessage(Exception ex)
}
///
- /// Implementation of using data from ADAL
+ /// Implementation of using data from ADAL
///
- private class AdalAccessToken : IAccessToken
+ private class AdalAccessToken : IRenewableToken
{
internal readonly AdalConfiguration Configuration;
internal AuthenticationResult AuthResult;
@@ -276,6 +276,8 @@ public string LoginType
return Authentication.LoginType.OrgId;
}
}
+
+ public DateTimeOffset ExpiresOn { get { return AuthResult.ExpiresOn; } }
}
}
}
diff --git a/src/Authentication/Authentication/UserTokenProvider.cs b/src/Authentication/Authentication/UserTokenProvider.cs
index 9fcca0de5e..fbf85e76dd 100644
--- a/src/Authentication/Authentication/UserTokenProvider.cs
+++ b/src/Authentication/Authentication/UserTokenProvider.cs
@@ -294,9 +294,9 @@ private string GetExceptionMessage(Exception ex)
}
///
- /// Implementation of using data from ADAL
+ /// Implementation of using data from ADAL
///
- private class AdalAccessToken : IAccessToken
+ private class AdalAccessToken : IRenewableToken
{
internal readonly AdalConfiguration Configuration;
internal AuthenticationResult AuthResult;
@@ -353,6 +353,8 @@ public string LoginType
return Authentication.LoginType.OrgId;
}
}
+
+ public DateTimeOffset ExpiresOn { get { return AuthResult.ExpiresOn; } }
}
public IAccessToken GetAccessTokenWithCertificate(
diff --git a/src/ScenarioTest.ResourceManager/Mocks/MockAccessToken.cs b/src/ScenarioTest.ResourceManager/Mocks/MockAccessToken.cs
index 1241197dc6..d7463ac720 100644
--- a/src/ScenarioTest.ResourceManager/Mocks/MockAccessToken.cs
+++ b/src/ScenarioTest.ResourceManager/Mocks/MockAccessToken.cs
@@ -17,7 +17,7 @@
namespace Microsoft.WindowsAzure.Commands.Common.Test.Mocks
{
- public class MockAccessToken : IAccessToken
+ public class MockAccessToken : IRenewableToken
{
private string _tenantId = String.Empty;
public void AuthorizeRequest(Action authTokenSetter)
@@ -34,5 +34,7 @@ public string TenantId
get { return _tenantId; }
set { _tenantId = value; }
}
+
+ public DateTimeOffset ExpiresOn { get; set; }
}
}
diff --git a/src/ScenarioTest/Mocks/MockAccessToken.cs b/src/ScenarioTest/Mocks/MockAccessToken.cs
index dfc6243901..faa8846bc4 100644
--- a/src/ScenarioTest/Mocks/MockAccessToken.cs
+++ b/src/ScenarioTest/Mocks/MockAccessToken.cs
@@ -17,7 +17,7 @@
namespace Microsoft.WindowsAzure.Commands.Common.Test.Mocks
{
- public class MockAccessToken : IAccessToken
+ public class MockAccessToken : IRenewableToken
{
public void AuthorizeRequest(Action authTokenSetter)
{
@@ -32,5 +32,7 @@ public string TenantId
{
get { return string.Empty; }
}
+
+ public DateTimeOffset ExpiresOn { get; set; }
}
}