Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[*]
end_of_line = crlf
trim_trailing_whitespace = true

[*.xml]
indent_style = space
Expand Down Expand Up @@ -28,4 +29,4 @@ dotnet_style_predefined_type_for_member_access = true:suggestion
dotnet_style_qualification_for_event = true:suggestion
dotnet_style_qualification_for_field = true:suggestion
dotnet_style_qualification_for_method = true:suggestion
dotnet_style_qualification_for_property = true:suggestion
dotnet_style_qualification_for_property = true:suggestion
9 changes: 5 additions & 4 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<!-- Enable Central Package Management (CPS) - https://learn.microsoft.com/en-us/nuget/consume-packages/Central-Package-Management -->
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>

<ItemGroup>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageVersion Include="MSTest.TestAdapter" Version="3.2.1" />
Expand All @@ -23,6 +23,7 @@
<PackageVersion Include="Microsoft.Identity.Client.Broker" Version="4.64.0" />
<PackageVersion Include="Microsoft.Identity.Client.NativeInterop" Version="0.16.2" />
<PackageVersion Include="Microsoft.PowerBI.Api" Version="2.14.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.15.0" />
<PackageVersion Include="System.Runtime.Serialization.Json" Version="4.3.0" />
<PackageVersion Include="Moq" Version="4.8.2" />
<PackageVersion Include="platyPS" Version="0.9.0" />
Expand All @@ -31,4 +32,4 @@
<PackageVersion Include="System.IO.Packaging" Version="9.0.4" />
<PackageVersion Include="coverlet.msbuild " Version="6.0.4" />
</ItemGroup>
</Project>
</Project>
4 changes: 3 additions & 1 deletion src/Common/Commands.Common.Test/TestProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ public class TestProfile : IPowerBIProfile
public string Thumbprint { get; set; }

public PowerBIProfileType LoginType { get; set; } = PowerBIProfileType.User;

public string AccessToken { get; set; }
}
}
}
4 changes: 3 additions & 1 deletion src/Common/Commands.Common/AuthenticationFactorySelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class AuthenticationFactorySelector : IAuthenticationFactory
private static IAuthenticationUserFactory UserAuthFactory;
private static IAuthenticationServicePrincipalFactory ServicePrincipalAuthFactory;
private static IAuthenticationBaseFactory BaseAuthFactory;

private void InitializeUserAuthenticationFactory(IPowerBILogger logger, IPowerBISettings settings)
{
if (UserAuthFactory == null)
Expand Down Expand Up @@ -76,6 +76,8 @@ public async Task<IAccessToken> Authenticate(IPowerBIProfile profile, IPowerBILo
return await this.Authenticate(profile.UserName, profile.Password, profile.Environment, logger, settings);
case PowerBIProfileType.Certificate:
return await this.Authenticate(profile.UserName, profile.Thumbprint, profile.Environment, logger, settings);
case PowerBIProfileType.BringYourOwnToken:
return new PowerBIAccessToken { AccessToken = profile.AccessToken, };
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it enough for customer? On the other hand, we return what has been passed in.

default:
throw new NotSupportedException();
}
Expand Down
5 changes: 5 additions & 0 deletions src/Common/Common.Abstractions/Interfaces/IPowerBIProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,10 @@ public interface IPowerBIProfile
/// Type of login used to create profile.
/// </summary>
PowerBIProfileType LoginType { get; }

/// <summary>
/// Access token that was brought by user.
/// </summary>
string AccessToken { get; }
}
}
5 changes: 5 additions & 0 deletions src/Common/Common.Abstractions/PowerBIProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,14 @@ public class PowerBIProfile : IPowerBIProfile

public string Thumbprint { get; }

public string AccessToken { get; }

public PowerBIProfile(IPowerBIEnvironment environment, IAccessToken token) =>
(this.Environment, this.TenantId, this.UserName, this.LoginType) = (environment, token.TenantId, token.UserName, PowerBIProfileType.User);

public PowerBIProfile(IPowerBIEnvironment environment, string accessToken) =>
(this.Environment, this.AccessToken, this.LoginType) = (environment, accessToken, PowerBIProfileType.BringYourOwnToken);

public PowerBIProfile(IPowerBIEnvironment environment, string userName, SecureString password, IAccessToken token, bool servicePrincipal = true) =>
(this.Environment, this.TenantId, this.UserName, this.Password, this.LoginType) = (environment, token.TenantId, userName, password, servicePrincipal ? PowerBIProfileType.ServicePrincipal : PowerBIProfileType.UserAndPassword);

Expand Down
3 changes: 2 additions & 1 deletion src/Common/Common.Abstractions/PowerBIProfileType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public enum PowerBIProfileType
User = 0,
ServicePrincipal = 1,
Certificate = 2,
UserAndPassword = 3
UserAndPassword = 3,
BringYourOwnToken = 4,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation;
using System.Security;
using Microsoft.IdentityModel.Tokens;
using Microsoft.PowerBI.Commands.Common.Test;
using Microsoft.PowerBI.Common.Abstractions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
Expand Down Expand Up @@ -144,13 +145,15 @@ public void ConnectPowerBIServiceWithDiscoveryUrl()
public void ConnectPowerBIServiceAccountServiceWithTenantId_PrincipalParameterSet()
{
// Arrange
using var secureString = new SecureString();

var initFactory = new TestPowerBICmdletNoClientInitFactory(false);
var testTenantName = "test.microsoftonline.com";
var cmdlet = new ConnectPowerBIServiceAccount(initFactory)
{
Tenant = testTenantName,
ServicePrincipal = true,
Credential = new PSCredential("appId", new SecureString()),
Credential = new PSCredential("appId", secureString),
ParameterSet = "ServicePrincipal"
};

Expand Down Expand Up @@ -181,5 +184,133 @@ public void ConnectPowerBIServiceAccountDiscoveryUrl_NullCustomEnvironment()
//Assert
Assert.Fail("Custom environment was not provided");
}

[TestMethod]
public void ConnectPowerBIServiceAccount_Illegal_Token_Format_Throws()
{
// Arrange
var factory = new TestPowerBICmdletNoClientInitFactory(setProfile: false);

var cmdlet = new ConnectPowerBIServiceAccount(factory)
{
Token = "thisjwtissowrong",
ParameterSet = ConnectPowerBIServiceAccount.BringYourOwnTokenParameterSet,
};

// Act & Assert
Assert.ThrowsException<SecurityTokenMalformedException>(cmdlet.InvokePowerBICmdlet);
}

[TestMethod]
public void ConnectPowerBIServiceAccount_Expired_Token_Throws()
{
// Arrange
var factory = new TestPowerBICmdletNoClientInitFactory(setProfile: false);

var cmdlet = new ConnectPowerBIServiceAccount(factory)
{
// this is a dummy generated expired token
Token = "eyJhbGciOiJIUzI1NiJ9.eyJ0ZXN0X2NsYWltIjp0cnVlLC"
+ "Jpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46Z"
+ "XhhbXBsZTphdWRpZW5jZSIsImV4cCI6MTc3MDcxNzUxNCwiaWF0I"
+ "joxNzcwNzE3NDU0fQ.8aM6WbtJkp8mOpWKsmFngPFIMdzGIQje1ZhKpHH_UVE",

ParameterSet = ConnectPowerBIServiceAccount.BringYourOwnTokenParameterSet,
};

// Act & Assert
Assert.ThrowsException<SecurityTokenExpiredException>(cmdlet.InvokePowerBICmdlet);
}

[TestMethod]
public void ConnectPowerBIServiceAccount_Valid_Token_Success()
{
// Arrange
// dummy generated token that will expire in 30 years (from 10022026)
var dummyToken = "eyJhbGciOiJIUzI1NiJ9.eyJ0ZXN0X2NsYWltIjp0cnVlLCJpc3MiOiJ1cm46ZXhhbXBsZT"
+ "ppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSIsImV4cCI6MjcxN"
+ "zQ0Njc4NSwiaWF0IjoxNzcwNzE4Nzg1fQ.nOXgwieIpeFB9Svxxt6Z4_RkWVWSiVJcxbBzlPTaQJQ";

var factory = new TestPowerBICmdletNoClientInitFactory(setProfile: false);

var cmdlet = new ConnectPowerBIServiceAccount(factory)
{
Token = dummyToken,
Environment = PowerBIEnvironmentType.Daily,
ParameterSet = ConnectPowerBIServiceAccount.BringYourOwnTokenParameterSet,
};

// Act
cmdlet.InvokePowerBICmdlet();

// Assert
var profile = factory.GetProfileFromStorage();
Assert.IsNotNull(profile);
Assert.AreEqual(dummyToken, profile.AccessToken);
Assert.AreEqual(PowerBIEnvironmentType.Daily, profile.Environment.Name);
Assert.AreEqual(PowerBIProfileType.BringYourOwnToken, profile.LoginType);
factory.AssertExpectedUnitTestResults([profile]);
}

[TestMethod]
public void ConnectPowerBIServiceAccount_BringYourOwnTokenParameterSet_Token_with_CertificateThumbPrint_Throws()
{
using (var ps = System.Management.Automation.PowerShell.Create())
{
// Arrange
ps.AddCommand(ProfileTestUtilities.ConnectPowerBIServiceAccountCmdletInfo);
ps.AddParameter(nameof(ConnectPowerBIServiceAccount.Token), "dummytoken");
ps.AddParameter(nameof(ConnectPowerBIServiceAccount.CertificateThumbprint), "dummycreds");

// Act & Assert
Assert.ThrowsException<ParameterBindingException>(ps.Invoke);
}
}

[TestMethod]
public void ConnectPowerBIServiceAccount_BringYourOwnTokenParameterSet_Token_with_ApplicationId_Throws()
{
using (var ps = System.Management.Automation.PowerShell.Create())
{
// Arrange
ps.AddCommand(ProfileTestUtilities.ConnectPowerBIServiceAccountCmdletInfo);
ps.AddParameter(nameof(ConnectPowerBIServiceAccount.Token), "dummytoken");
ps.AddParameter(nameof(ConnectPowerBIServiceAccount.ApplicationId), "applicationId");

// Act & Assert
Assert.ThrowsException<ParameterBindingException>(ps.Invoke);
}
}

[TestMethod]
public void ConnectPowerBIServiceAccount_BringYourOwnTokenParameterSet_Token_with_Credential_Throws()
{
using (var secureString = new SecureString())
using (var ps = System.Management.Automation.PowerShell.Create())
{
// Arrange
ps.AddCommand(ProfileTestUtilities.ConnectPowerBIServiceAccountCmdletInfo);
ps.AddParameter(nameof(ConnectPowerBIServiceAccount.Token), "dummytoken");
ps.AddParameter(nameof(ConnectPowerBIServiceAccount.Credential), new PSCredential("password", secureString));

// Act & Assert
Assert.ThrowsException<ParameterBindingException>(ps.Invoke);
}
}

[TestMethod]
public void ConnectPowerBIServiceAccount_BringYourOwnTokenParameterSet_Token_with_ServicePrincipal_Throws()
{
using (var ps = System.Management.Automation.PowerShell.Create())
{
// Arrange
ps.AddCommand(ProfileTestUtilities.ConnectPowerBIServiceAccountCmdletInfo);
ps.AddParameter(nameof(ConnectPowerBIServiceAccount.Token), "dummytoken");
ps.AddParameter(nameof(ConnectPowerBIServiceAccount.ServicePrincipal), new SwitchParameter());

// Act & Assert
Assert.ThrowsException<ParameterBindingException>(ps.Invoke);
}
}
}
}
7 changes: 4 additions & 3 deletions src/Modules/Profile/Commands.Profile/Commands.Profile.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
<AssemblyName>Microsoft.PowerBI.Commands.Profile</AssemblyName>
<RootNamespace>Microsoft.PowerBI.Commands.Profile</RootNamespace>
</PropertyGroup>

<!-- NuGet Package Properties -->
<PropertyGroup>
<IsPackable>true</IsPackable>
<PackageId>MicrosoftPowerBIMgmt.Profile</PackageId>
<Description>Microsoft Power BI PowerShell - Profile credential management cmdlets for Microsoft Power BI</Description>
<PackageTags>PowerBI;Profile;Authentication;Environment</PackageTags>
</PropertyGroup>

<ItemGroup>
<None Remove="Microsoft.PowerBI.Commands.Profile.format.ps1xml" />
<None Remove="Microsoft.PowerBI.Commands.Profile.types.ps1xml" />
<None Remove="MicrosoftPowerBIMgmt.Profile.psd1" />
</ItemGroup>

<ItemGroup>
<Content Include="Microsoft.PowerBI.Commands.Profile.format.ps1xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand All @@ -37,6 +37,7 @@
<PackageReference Include="Microsoft.Rest.ClientRuntime">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading
Loading