1. Prerequisites

How to Build .NET Project with CLI

\# Open Developer Command Prompt for VS 2019 and goto the project directory, then type the follow commands:

> msbuild -t:Clean (1)
> msbuild -t:Build (2)
> msbuild (3)
> msbuild -p:Configuration=Release (4)
1 Clean build outputs of a .NET project.
2 Build a .NET project.
3 Build a .NET project with default build target.
4 Build a .NET project with Release configuration.

\# Open any Command Prompt or Bash Console and goto the project direcotry, then type the follow commands:

$ dotnet clean (1)
$ dotnet build (2)
$ dotnet build -c Release (3)
1 Clean build outputs of a .NET project.
2 Build a .NET project.
3 Build a .NET project with Release configuration.

2. Reporting Services Custom Security

You must first compile and install the extension. The procedure assumes that you have installed Reporting Services to the default location: C:\Program Files\Microsoft Power BI Report Server\PBIRS. This location will be referred to throughout the remainder of this topic as <install>.

2.1. Step 1. Build the Extension Project

$ git clone https://github.com/qqbuby/PowerBI.ReportingServices.Extensions.git
git clone https://github.com/qqbuby/PowerBI.ReportingServices.Extensions.git
Cloning into 'PowerBI.ReportingServices.Extensions'...
remote: Enumerating objects: 63, done.
remote: Counting objects: 100% (63/63), done.
remote: Compressing objects: 100% (54/54), done.
remote: Total 63 (delta 15), reused 52 (delta 6), pack-reused 0
Receiving objects: 100% (63/63), 71.26 KiB | 513.00 KiB/s, done.
Resolving deltas: 100% (15/15), done.
$ cd PowerBI.ReportingServices.Extensions
$ dotnet build
Microsoft (R) Build Engine version 16.10.2+857e5a733 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  Restored ...\src\PowerBI.ReportingServices.Security\PowerBI.ReportingServices.Security.csproj (in 209 ms).
  PowerBI.ReportingServices.Security -> ...\src\PowerBI.ReportingServices.Security\bin\Debug\net48\PowerBI.ReportingServices.Security.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:03.51
To compile the Project using Visual Studio
  • Open PowerBI.ReportingServices.sln in Microsoft Visual Studio.

  • In Solution Explorer, select the PowerBI.ReportingServices.Security project.

  • Look at the PowerBI.ReportingServices.Security project’s Dependencies→Assemblies.

    • If you do not see Microsoft.ReportingServices.Interfaces.dll, then complete the following steps:

      • On the Assemblies menu, right click Add Assembly Reference.... The Add References dialog box opens.

      • Click Browse, and find Microsoft.ReportingServices.Interfaces on your local drive. By default, the assembly is in the <install>\ReportServer\bin directory. Click OK. The selected reference is added to your project.

    • If you do not see EntityFramework.dll, EntityFramework.SqlServer.dll, Microsoft.Extensions.DependencyInjection.dll and Microsoft.Extensions.DependencyInjection.Abstractions.dll, then complete the following steps:

      • On the Assemblies menu, right click Add Assembly Reference.... The Add References dialog box opens.

      • Click Browse, and find these assemblies on your local drive. By default, the assembly is in the <install>\Portal directory- Click OK. The selected reference is added to your project.

  • On the Build menu, click Build Solution.

Debugging

To debug the extension, you might want to attach the debugger to both ReportingServicesService.exe, RSPortal.exe and RSPowerBI.exe. And add breakpoints to the methods implementing the interface IAuthenticationExtension2 and IAuthorizationExtension.

Troubleshooting

If the report server cann’t work expectedly, you may need to analyze the reprot server log files at <install>/LogFiles, especially the following highlight files :

$ ls -1 LogFiles/
ASManagedRoot_2021_11_05_09_56_18.log
FlightRecorderCurrent.trc
msmdsrv.log
ReportingServicesService_2021_11_05_09_56_17.log
ReportingServicesWMI_2021_11_05_09_54_26.log
RSHostingService_2021_11_05_09_55_46.log
RSManagement_2021_11_05_09_55_47.log
RSOffice_2021_11_05_09_56_17.log
RSPortal_2021_11_05_09_56_17.log
RSPowerBI_2021_11_05_09_56_17.log

2.2. Step 2: Deployment and Configuration

# The Build Outputs of the Security Extenstion Project
$ ls src/PowerBI.ReportingServices.Security/bin/Debug/net48/
EntityFramework.dll*                   Microsoft.Extensions.DependencyInjection.Abstractions.dll*
EntityFramework.SqlServer.dll*         Microsoft.Extensions.DependencyInjection.dll*
PowerBI.ReportingServices.Security.dll*  Microsoft.ReportingServices.Interfaces.dll*
PowerBI.ReportingServices.Security.pdb   Sso.aspx

2.2.1. To deploy the security extension

  • Copy the Sso.aspx page to the <install>\ReportServer directory.

  • Copy all the *.dll and *.pdb to the follow directories:

    • <install>\ReportServer\bin

    • <install>\Portal

    • <install>\PowerBI

2.2.2. Modify files in the <install>\ReportServer direcotry

  • To modify the rsreportserver.config file.

  • Open the rsreportserver.config file with Visual Studio or a simple text editor such as Notepad. rsreportserver.config is located in the <install>\ReportServer directory.

  • Locate the <AuthenticationTypes> element and modify the settings as follows:

    <Authentication>
      <AuthenticationTypes>
        <!--<RSWindowsNTLM/>--> (1)
        <Custom/>
      </AuthenticationTypes>
      <RSWindowsExtendedProtectionLevel>Off</RSWindowsExtendedProtectionLevel>
      <RSWindowsExtendedProtectionScenario>Proxy</RSWindowsExtendedProtectionScenario>
      <EnableAuthPersistence>true</EnableAuthPersistence>
    </Authentication>
    1 Note that you cannot use Custom with other authentication types.
  • Locate the <Security> and <Authentication> elements, within the <Extensions> element, and modify the settings as follows:

    <Security>
      <Extension Name="Forms" Type="PowerBI.ReportingServices.Security.Authorization, PowerBI.ReportingServices.Security">
        <Configuration>
        <AdminConfiguration>
            <UserName>admin1@local.me,admin2@google.com</UserName> (1)
          </AdminConfiguration>
        </Configuration>
      </Extension>
      <!--<Extension Name="Windows" Type="Microsoft.ReportingServices.Authorization.WindowsAuthorization, Microsoft.ReportingServices.Authorization"/>-->
    </Security>
    1 Note that you should specify one or many administrators here.
    <Authentication>
      <Extension Name="Forms" Type="PowerBI.ReportingServices.Security.Cas.Authentication, PowerBI.ReportingServices.Security"/>
      <!--<Extension Name="Windows" Type="Microsoft.ReportingServices.Authentication.WindowsAuthentication, Microsoft.ReportingServices.Authorization"/>-->
    </Authentication>

2.2.3. To modify the web.config file for Report Server

  • Open the web.config file in a text editor. By default, the file is in the <install>\ReportServer directory.

  • Locate the <identity> element and set the Impersonate attribute to false.

    <identity impersonate="false" />
    <!--<identity impersonate="true" />-->
  • Locate the <authentication> element and change the Mode attribute to Forms. Also, add the following <forms> element as a child of the <authentication> element and set the loginUrl, name, timeout, path, requireSSL, and cookieSameSite attributes as follows:

    <!--<authentication mode="Windows" />-->
    <authentication mode="Forms">
      <forms loginUrl="Sso.aspx" name="X-RS-TOKEN" timeout="60" path="/" requireSSL="true" cookieSameSite="None">
      </forms>
    </authentication>

    For local development, if you cann’t debug with HTTPS, you should delete both the requireSSL and cookieSameSite attributes.

    <!--<authentication mode="Windows" />-->
    <authentication mode="Forms">
      <forms loginUrl="Sso.aspx" name="X-RS-TOKEN" timeout="60"  path="/">
      </forms>
    </authentication>
  • Add the following <authorization> element directly after the <authentication> element.

    <authorization>
      <deny users="?" />
    </authorization>

    This will deny unauthenticated users the right to access the report server. The previously established loginUrl attribute of the <authentication> element will redirect unauthenticated requests to the Sso.aspx page.

  • Configuration <appSettings> and <connectionStrings> inner the element <configuration> as below.

    <appSettings>
      <add key="cas.baseaddress" value="https://cas.example.com" />
      <add key="cas.login.path" value="/cas/login" />
      <add key="cas.service.validate.path" value="/cas/serviceValidate" />
    </appSettings>
    <connectionStrings>
      <add name="cas.useraccounts" (1)
           connectionString="Data Source=mssql;Initial Catalog=UserAccounts;Persist Security Info=True;User ID=sa;Password=******"
           providerName="System.Data.SqlClient" />
    </connectionStrings>
    1 Your should modify the Data Source with the Server Name of your MSSQL, User ID and Password with your only SQL Server Authentication credentials.
  • Locate the <trust> element and update it as follows:

    <!--<securityPolicy>
      <trustLevel name="RosettaSrv" policyFile="rssrvpolicy.config" />
    </securityPolicy>
    <trust level="RosettaSrv" originUrl="" egacyCasModel="true" />-->
    <trust level="Full" />

2.2.4. To modify the RSPortal.exe.config file for Report Server Portal

  • Open the web.config file in a text editor. By default, the file is in the <install>\Portal directory.

  • Configuration <connectionStrings> under the <configuration> as same as web.config as below.

<connectionStrings>
  <add name="cas.useraccounts"
       connectionString="Data Source=mssql;Initial Catalog=UserAccounts;Persist Security Info=True;User ID=sa;Password=******"
       providerName="System.Data.SqlClient" />
</connectionStrings>

2.3. Step 3: Generate Machine Keys

Using Forms authentication requires that all report server processes can access the authentication cookie. This involves configuring a machine key and decryption algorithm — a familiar step for those who had previously setup SSRS to work in scale-out environments.

Generate and add <MachineKey> under <Configuration> in your rsreportserver.config file.

<MachineKey ValidationKey="[YOUR KEY]" DecryptionKey="[YOUR KEY]" Validation="AES" Decryption="AES" />

The follow code snippet is a sample:

<Configuration>
  <MachineKey
    ValidationKey="C9A00A9C93B7AC6B8B3C27054DEDA40FDE08D20C481E808042F32784B3A7F5EF"
    DecryptionKey="8F3D5F7B29A0EB685B61299502490226DA98BCB73B024F78651C24517A5ACCB9"
    Validation="AES"
    Decryption="AES"/>
    . . .

Check the casing of the attributes, it should be Pascal Casing as the example above.

There is not need for a <system.web> entry.

You should use a validation key specific for you deployment, there are several tools to generate the keys such as Internet Information Services Manager (IIS), or the online machine-key-generator.

2.4. Step 4: Configure Passthrough cookies

The new portal and the reportserver communicate using internal soap APIs for some of its operations. When additional cookies are required to be passed from the portal to the server the PassThroughCookies properties is still available. More Details: https://msdn.microsoft.com/en-us/library/ms345241.aspx. In the rsreportserver.config file add following under <UI>.

<UI>
  <ReportServerUrl></ReportServerUrl>
  <PageCountMode>Estimate</PageCountMode>
  <CustomAuthenticationUI>
    <PassThroughCookies>
      <PassThroughCookie>X-RS-TOKEN</PassThroughCookie>
    </PassThroughCookies>
  </CustomAuthenticationUI>
</UI>

3. Security Extensions Overview

Reporting Services provides an extensible architecture that allows you to plug in custom or forms-based authentication modules. You might consider implementing a custom authentication extension if deployment requirements do not include Windows integrated security or Basic authentication. The most common scenario for using custom authentication is to support Internet or extranet access to a Web application. Replacing the default Windows Authentication extension with a custom authentication extension gives you more control over how external users are granted access to the report server.

In practice, deploying a custom authentication extension requires multiple steps that include copying assemblies and application files, modifying configuration files, and testing.

Creating a custom authentication extension requires custom code and expertise in ASP.NET security. If you do not want to create a custom authentication extension, you can use Microsoft Active Directory groups and accounts, but you should greatly reduce the scope of a report server deployment. For more information about custom authentication, see Implementing a Security Extension.

We recommend that you use Windows Authentication if at all possible. However, custom authentication and authorization for Reporting Services may be appropriate in the following two cases:

  • You have an Internet or extranet application that cannot use Windows accounts.

  • You have custom-defined users and roles and need to provide a matching authorization scheme in Reporting Services.

Security Extensions Overview

As shown in the above figure, authentication and authorization occur as follows:

1 A user tries to access the web portal by using a URL and is redirected to a form that collects user credentials for the client application.
2 The user submits credentials to the form.
3 The user credentials are submitted to the Reporting Services Web service through the LogonUser method.
4 The Web service calls the customer-supplied security extension and verifies that the user name and password exist in the custom security authority.
5 After authentication, the Web service creates an authentication ticket (known as a "cookie"), manages the ticket, and verifies the user’s role for the Home page of the web portal.
6 The Web service returns the cookie to the browser and displays the appropriate user interface in the web portal.
7 After the user is authenticated, the browser makes requests to the web portal while transmitting the cookie in the HTTP header. These requests are in response to user actions within the web portal.
8 The cookie is transmitted in the HTTP header to the Web service along with the requested user operation.
9 The cookie is validated, and if it is valid, the report server returns the security descriptor and other information relating to the requested operation from the report server database.
10 If the cookie is valid, the report server makes a call to the security extension to check if the user is authorized to perform the specific operation.
11 If the user is authorized, the report server performs the requested operation and returns control to the caller.
12 After the user is authenticated, URL access to the report server uses the same cookie. The cookie is transmitted in the HTTP header.
13 The user continues to request operations on the report server until the session has ended.

3.1. Authentication in Reporting Services

Authentication is the process of establishing a user’s right to an identity. There are many techniques that you can use to authenticate a user. The most common way is to use passwords. When you implement Forms Authentication, for example, you want an implementation that queries users for credentials (usually by some interface that requests a login name and password) and then validates users against a data store, such as a database table or configuration file. If the credentials can’t be validated, the authentication process fails and the user will assume an anonymous identity.

In Reporting Services, the Windows operating system handles the authentication of users either through integrated security or through the explicit reception and validation of user credentials. Custom authentication can be developed in Reporting Services to support additional authentication schemes. This is made possible through the security extension interface IAuthenticationExtension2. All extensions inherit from the IExtension base interface for any extension deployed and used by the report server. IExtension, as well as IAuthenticationExtension2, are members of the Microsoft.ReportingServices.Interfaces namespace.

Authentication Flow

As shown in the above figure, the authentication process is as follows:

1 A client application calls the Web service LogonUser method to authenticate a user.
2 The Web service makes a call to the LogonUser method of your security extension, specifically, the class that implements IAuthenticationExtension2.
3 Your implementation of LogonUser validates the user name and password in the user store or security authority.
4 Upon successful authentication, the Web service creates a cookie and manages it for the session.
5 The Web service returns the authentication ticket to the calling application on the HTTP header.

3.2. Authorization in Reporting Services

Authorization is the process of determining whether an identity should be granted the requested type of access to a given resource in the report server database. Reporting Services uses a role-based authorization architecture that grants a user access to a given resource based on the user’s role assignment for the application. Security extensions for Reporting Services contain an implementation of an authorization component that is used to grant access to users once they are authenticated on the report server. Authorization is invoked when a user attempts to perform an operation on the system or a report server item through the SOAP API and via URL access. This is made possible through the security extension interface IAuthorizationExtension. As stated previously, all extensions inherit from IExtension the base interface for any extension that you deploy. IExtension and IAuthorizationExtension are members of the Microsoft.ReportingServices.Interfaces namespace.

Authorization Flow

As shown in the Figure 3, authorization follows this sequence:

1 Once authenticated, client applications make requests to the report server through the Reporting Services Web service methods. An authentication ticket is passed to the report server in the form of a cookie in the HTTP header of each Web request.
2 The cookie is validated prior to any access check.
3 Once the cookie is validated, the report server calls GetUserInfo and the user is given an identity.
4 The user attempts an operation through the Reporting Services Web service.
5 The report server calls the CheckAccess method.
6 The security descriptor is retrieved and passed to a custom security extension implementation of CheckAccess. At this point, the user, group, or computer is compared to the security descriptor of the item being accessed and is authorized to perform the requested operation.
7 If the user is authorized, the Web service performs the operation and returns a response to the calling application.

4. References