F# with sqlclr in a reasonably safe way and scripted assembly

送分小仙女□ 提交于 2019-12-06 02:32:05

I'm skeptical of the approach shown in your first link ( http://richardminerich.com/2015/12/a-safer-way-to-use-f-with-sql-clr/ ) as it does not directly show the loading of the FSharp.Core library, hence it is not clear that the author did not have to set TRUSTWORTHY ON in order to at least get that part working. What seems highly suspicious is that in Step 5, the Asymmetric Key-based Login is granted the wrong permission:

GRANT EXTERNAL ACCESS ASSEMBLY TO FSHARP_CLR_Login

Granting EXTERNAL ACCESS ASSEMBLY does not allow for setting an Assembly to UNSAFE. That requires the UNSAFE ASSEMBLY permission. It could be a copy / paste error when writing the post, but no proof is shown (i.e. from sys.databases) that TRUSTWORTHY is currently OFF, or that the author's code wasn't working prior to creating that Login and granting that permission to it.

So, I just tried this by installing the most recent build of FSharp.Core – 4.1.2 – and here is what I found:

  1. Confirm that TRUSTWORTHY is OFF (i.e. 0) via:

    SELECT [name], is_trustworthy_on FROM sys.databases WHERE [database_id] = DB_ID();
    
  2. Attempt to load FSharp.Core as SAFE, just to see if it works:

    USE [TestDB];
    
    CREATE ASSEMBLY [FSharp.Core]
    FROM N'C:\path\to\project\packages\FSharp.Core.4.1.2\lib\net45\FSharp.Core.dll'
    WITH PERMISSION_SET = SAFE;
    

    That receives the following error:

    Msg 6211, Level 16, State 1, Line 32
    CREATE ASSEMBLY failed because type 'Microsoft.FSharp.Collections.FSharpMap`2' in safe assembly 'FSharp.Core' has a static field 'empty'. Attributes of static fields in safe assemblies must be marked readonly in Visual C#, ReadOnly in Visual Basic, or initonly in Visual C++ and intermediate language.

  3. Attempt to load FSharp.Core again, but as UNSAFE:

    USE [TestDB];
    
    CREATE ASSEMBLY [FSharp.Core]
    FROM N'C:\path\to\project\packages\FSharp.Core.4.1.2\lib\net45\FSharp.Core.dll'
    WITH PERMISSION_SET = UNSAFE;
    

    That works. But, I didn't set the Database to TRUSTWORTHY ON, nor did I create a Login and grant it the EXTERNAL ACCESS ASSEMBLY permission. Meaning: the violation is probably found via a run-time verification instead of a load-time verification. And I have no way to test beyond this part, but I would expect that an error will occur.

  4. If an error does occur regarding the UNSAFE Permission Set for this Assembly, then you can handle that without resorting to setting TRUSTWORTHY ON, but you will need to create a Certificate in master and a Certficate-based Login:

    USE [master];
    
    CREATE CERTIFICATE [FSharpCert45]
    FROM EXECUTABLE FILE =
            N'C:\path\to\project\packages\FSharp.Core.4.1.2\lib\net45\FSharp.Core.dll';
    
    CREATE LOGIN [FSharpLogin45] FROM CERTIFICATE [FSharpCert45];
    
    GRANT UNSAFE ASSEMBLY TO [FSharpLogin45];
    
  5. IF your Assembly is also required to be marked as UNSAFE, then you can create an Asymmetric Key from the DLL in master and then a Key-based Login from that Asymmetric Key, and then grant that Key-based Login the UNSAFE ASSEMBLY permission. (this assumes that your Assembly is signed -- and protected with a password)

  6. Of course, all of the above assumes that you can get the DLL onto the server or at least onto a share that the SQL Server service account has access to, and you did mention wanting to deploy this via hex bytes. That should be possible by doing:

    1. In Visual Studio, under "References" in the "Solution Explorer", go to the "Properties" for FSharp.Core and set Model Aware to True and Permission Set to Unsafe. This will cause the publish process to include the DLL in the build script.
    2. If the DLL is already in your target DB, then it probably won't generate the CREATE ASSEMBLY statement for this Assembly since publish scripts are incremental changes. If this is the case, then go to the project properties, and under Project Settings, check the box for Create script (.sql file) (if not already checked). This will cause the build process to always produce a _Create.sql script, and in there will definitely be the CREATE ASSEMBLY statement for FSharp.Core.
    3. That CREATE ASSEMBLY [FSharp.Core] FROM 0x... statement will obviously be used to load the Assembly into the target DB (i.e. where your Assembly is also getting loaded into).
    4. That CREATE ASSEMBLY [FSharp.Core] FROM 0x... statement will also be your ticket to creating the objects in master as follows:

      USE [master];
      
      CREATE ASSEMBLY [FSharp.Core]
      FROM 0x4D....
      WITH PERMISSION_SET = UNSAFE;
      
      CREATE CERTIFICATE [FSharpCert45]
      FROM ASSEMBLY [FSharp.Core];
      
      DROP ASSEMBLY [FSharp.Core];
      
      CREATE LOGIN [FSharpLogin45] FROM CERTIFICATE [FSharpCert45];
      
      GRANT UNSAFE ASSEMBLY TO [FSharpLogin45];
      

      This worked for me on SQL Server 2012, the only difference being I used the file path instead of the hex bytes.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!