4
votes

I'm building a SQL Server Reporting Services (SSRS) report. The end user viewing the report can select certain input parameters, in this case locations. The locations the user can select are depending on Active Directory Group Membership, so I'm trying to assert group membership in a custom report function.

(Since the report uses a common datasource connecting to an Oracle database, delegating group membership to the database is not an option)

I've written the following custom code inside a proof-of-concept report:

Function CheckRight(name As String) As String
  Try
     Dim nameParts = name.Split("/")
     Dim user = name(1) + "@" + name(0)
     Dim inrole As Boolean = IsInGroup(user, "Domain Users")
     Return Iif(inrole, "Yes", "No")
  Catch ex As Exception
    Return ex.Message
  End Try
End Function

Function IsInGroup(user As String, group As String) As Boolean
  Dim identity AS System.Security.Principal.WindowsIdentity
  identity = New System.Security.Principal.WindowsIdentity(user)
  Dim principal = New System.Security.Principal.WindowsPrincipal(identity)
  Return principal.IsInRole(group)
End Function

I'm displaying the result in my report using an expression:

=Code.CheckRight(User!UserID)

Instead of displaying 'Yes' or 'No', an error is displayed:

Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.

(or in Dutch: 'De aanvraag voor machtiging van type System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is mislukt.')

I'm using Visual Studio 2012, So I'll my PrivateAssemblies is located in C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\PrivateAssemblies.


ANSWER

based on adriano-repetti's answer


I edited PrivateAssemblies\RSPreviewPolicy.config, and got it to work locally:

<NamedPermissionSets>                       

  <!-- added this extra permission set at the bottom: -->

  <PermissionSet 
                 class="NamedPermissionSet"
                 version="1"
                 Name="PermissionSetForIsInRole"
                 Description="Permission set that grants rights to WindowsPrincipal.IsInRole.">
    <IPermission 
                 class="SecurityPermission"
                 version="1"
                 Flags="Execution,ControlPrincipal"/>
  </PermissionSet>  
</NamedPermissionSets>

<PolicyLevel>
  <Codegroup class="FirstMatchCodeGroup" ...>
    <CodeGroup 
        class="FirstMatchCodeGroup"
        version="1"
        PermissionSetName="Nothing">
      <IMembershipCondition 
          class="AllMembershipCondition"
          version="1"
      />
        <!-- changed 'Execution' to 'PermissionSetForIsInRole' here: -->
        <CodeGroup
            class="UnionCodeGroup"
            version="1"
            PermissionSetName="PermissionSetForIsInRole"
            Name="Report_Expressions_Default_Permissions"
            Description="This code group grants default permissions for code in report expressions and Code element. ">
          <IMembershipCondition
              class="StrongNameMembershipCondition"
              version="1" 
              PublicKeyBlob="0024000..."
          />
      </CodeGroup>
  </CodeGroup>
</PolicyLevel>

SOME NOTES


  • Do not try to Assert the right. This results in "Cannot perform CAS Asserts in Security Transparent methods", for the reason described in adriano-repetti's answer.
  • It would probably also have been possible to modify the 'execution' permission.
  • https://msdn.microsoft.com/en-us/library/ms154466.aspx warns "Code that calls external assemblies or protected resources should be incorporated into a custom assembly for use in reports. Doing so gives you more control over the permissions requested and asserted by your code. You should not make calls to secure methods within the Code element. Doing so requires you to grant FullTrust to the report expression host and grants all custom code full access to the CLR."
  • A list of possible security flags can be found at https://msdn.microsoft.com/en-us/library/system.security.permissions.securitypermissionflag(v=vs.110).aspx
  • The RSPreviewPolicy.config is used locally only, for previewing locally. On production you need to edit C:\Program Files\Microsoft SQL Server\MSRS11.MSSQLSERVER\Reporting Services\ReportServer\bin\RSReportServerServices.exe.config. According to https://msdn.microsoft.com/en-us/library/bb630448.aspx - I haven't done this yet.
1

1 Answers

0
votes

WindowsPrincipal.IsInRole() method requires SecurityPermissionFlag.ControlPrincipal permission which by default isn't granted to custom code in your reports.

You may change your configuration to include a named permission-set (please also refer to that article for more details about this issue):

<PermissionSet class="NamedPermissionSet"
  version="1"
  Name="PermissionSetForIsInRole"
  Description="Permission set that grants rights to WindowsPrincipal.IsInRole.">
    <IPermission class="SecurityPermission"
      version="1"
      Flags="Execution, ControlPrincipal"/>
</PermissionSet>

Don't forget to associate this permission set with right <CodeGroup> (in your case Report_Expressions_Default_Permissions) and in the right configuration file.

Will this affect your overall security? Of course yes then you should grant only required rights and only to reports that require them. If security is correctly configured for your SSRS reports then this should not be an issue.

About your second version it doesn't work because transparent code (code executed in SSRS) is transparent to security and it can't assert/change security directly (see also rule CA2140: Transparent code must not reference security critical items.)

Transparency is an enforcement mechanism that separates code that runs as part of the application from code that runs as part of the infrastructure. Transparency draws a barrier between code that can do privileged things (critical code), such as calling native code, and code that cannot (transparent code). Transparent code can execute commands within the bounds of the permission set it is operating in, but cannot execute, derive from, or contain critical code.