Written by

Senior Startups and Community Programs Manager at InterSystems Corporation
Question Evgeny Shvarov · Jun 9, 2017

Caché Classes: How to Make a View on a Class to Manage Property Level Security?

Hi, Community!

Suppose I have class A with properties P1 and P2.

I want to introduce class B, which would have same records as Class A, but only  one property - P2.

What is the easiest  way to manage it assuming that I would like to use Class A to add records and be available for any operations to Users with Role A.

And I would like to introduce class B for Users with role B for read-only access.  Preferably they shouldn't even be aware of Class A and P1 existence .

What is the easiest way to introduce it and manage it?

Use some proxy-classes?  Property-level security?

Or to Introduce usual class B with only property P2 and manage the update operations together with Class A?

Comments

Evgeny Shvarov  Jun 9, 2017 to Eduard Lebedyuk

VIews work for SQL access. I really need a kind of view, but for classes paradigm: so I could have access to Class B property P2 with Caché object access.

0
Evgeny Shvarov  Jun 9, 2017 to Vitaliy Serdtsev

Thanks, Vitaly!

That looks exactly like what I want. I'll give it a try. Except with not very clear magic with SQLStorage. 

Is there any way to "generate" compatible storage? And why SQLStorage? Why not default CachéStorage, but copy-pasted from Class A?

0
Vitaliy Serdtsev · Jun 9, 2017

If you only need SQL access, then will be easier to create a view (CREATE VIEW), if need both, then - %CacheSQLStorage, e.g.:

<FONT COLOR="#000080">Class demo.A Extends %Persistent
</FONT><FONT COLOR="#000000">{

</FONT><FONT COLOR="#000080">Property </FONT><FONT COLOR="#000000">P1;

</FONT><FONT COLOR="#000080">Property </FONT><FONT COLOR="#000000">P2;

</FONT><FONT COLOR="#000080">ClassMethod </FONT><FONT COLOR="#000000">Fill() {   </FONT><FONT COLOR="#0000ff">d </FONT><FONT COLOR="#000000">..</FONT><FONT COLOR="#0000ff">%KillExtent</FONT><FONT COLOR="#000000">()      </FONT><FONT COLOR="#0000ff">f </FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">=1:1:3 </FONT><FONT COLOR="#800080">{     </FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">t</FONT><FONT COLOR="#000000">=..</FONT><FONT COLOR="#0000ff">%New</FONT><FONT COLOR="#000000">()     </FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">t</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">P1</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"P1_"</FONT><FONT COLOR="#000000"></FONT><FONT COLOR="#800000">i     </FONT><FONT COLOR="#0000ff">s </FONT><FONT COLOR="#800000">t</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">P2</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"P2"</FONT><FONT COLOR="#000000">_</FONT><FONT COLOR="#800000">i     </FONT><FONT COLOR="#0000ff">d </FONT><FONT COLOR="#800000">t</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">%Save</FONT><FONT COLOR="#000000">()   </FONT><FONT COLOR="#800080">} </FONT><FONT COLOR="#000000">}

</FONT><FONT COLOR="#000080">Storage </FONT><FONT COLOR="#000000">Default { <<FONT COLOR="#000080">Data </FONT><FONT COLOR="#800000">name</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"ADefaultData"</FONT><FONT COLOR="#000000">>   <</FONT><FONT COLOR="#000080">Value </FONT><FONT COLOR="#800000">name</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"1"</FONT><FONT COLOR="#000000">>     <</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">>%%CLASSNAME</</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">>   </</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">>   <</FONT><FONT COLOR="#000080">Value </FONT><FONT COLOR="#800000">name</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"2"</FONT><FONT COLOR="#000000">>     <</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">>P1</</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">>   </</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">>   <</FONT><FONT COLOR="#000080">Value </FONT><FONT COLOR="#800000">name</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"3"</FONT><FONT COLOR="#000000">>     <</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">>P2</</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">>   </</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">> </</FONT><FONT COLOR="#000080">Data</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">DataLocation</FONT><FONT COLOR="#000000">>^demo.AD</</FONT><FONT COLOR="#000080">DataLocation</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">DefaultData</FONT><FONT COLOR="#000000">>ADefaultData</</FONT><FONT COLOR="#000080">DefaultData</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">IdLocation</FONT><FONT COLOR="#000000">>^demo.AD</</FONT><FONT COLOR="#000080">IdLocation</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">IndexLocation</FONT><FONT COLOR="#000000">>^demo.AI</</FONT><FONT COLOR="#000080">IndexLocation</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">StreamLocation</FONT><FONT COLOR="#000000">>^demo.AS</</FONT><FONT COLOR="#000080">StreamLocation</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">Type</FONT><FONT COLOR="#000000">>%Library.CacheStorage</</FONT><FONT COLOR="#000080">Type</FONT><FONT COLOR="#000000">> </FONT>}

}</FONT>

<FONT COLOR="#000080">Class demo.B Extends %Persistent </FONT><FONT COLOR="#000000">[ </FONT><FONT COLOR="#000080">Final</FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#000080">StorageStrategy </FONT><FONT COLOR="#000000">= Default ] {

</FONT><FONT COLOR="#000080">Parameter </FONT><FONT COLOR="#000000">READONLY = </FONT><FONT COLOR="#000080">1</FONT><FONT COLOR="#000000">;

</FONT><FONT COLOR="#000080">Property </FONT><FONT COLOR="#000000">P2;

</FONT><FONT COLOR="#000080">Storage </FONT><FONT COLOR="#000000">Default { <<FONT COLOR="#000080">SQLMap </FONT><FONT COLOR="#800000">name</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"BDefaultData"</FONT><FONT COLOR="#000000">>   <</FONT><FONT COLOR="#000080">Data </FONT><FONT COLOR="#800000">name</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"P2"</FONT><FONT COLOR="#000000">>     <</FONT><FONT COLOR="#000080">Piece</FONT><FONT COLOR="#000000">>3</</FONT><FONT COLOR="#000080">Piece</FONT><FONT COLOR="#000000">>   </</FONT><FONT COLOR="#000080">Data</FONT><FONT COLOR="#000000">>   <</FONT><FONT COLOR="#000080">Global</FONT><FONT COLOR="#000000">>^demo.AD</</FONT><FONT COLOR="#000080">Global</FONT><FONT COLOR="#000000">>   <</FONT><FONT COLOR="#000080">RowIdSpec </FONT><FONT COLOR="#800000">name</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"1"</FONT><FONT COLOR="#000000">>     <</FONT><FONT COLOR="#000080">Expression</FONT><FONT COLOR="#000000">>{L1}</</FONT><FONT COLOR="#000080">Expression</FONT><FONT COLOR="#000000">>     <</FONT><FONT COLOR="#000080">Field</FONT><FONT COLOR="#000000">>ID</</FONT><FONT COLOR="#000080">Field</FONT><FONT COLOR="#000000">>   </</FONT><FONT COLOR="#000080">RowIdSpec</FONT><FONT COLOR="#000000">>   <</FONT><FONT COLOR="#000080">Subscript </FONT><FONT COLOR="#800000">name</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"1"</FONT><FONT COLOR="#000000">>     <</FONT><FONT COLOR="#000080">Expression</FONT><FONT COLOR="#000000">>{ID}</</FONT><FONT COLOR="#000080">Expression</FONT><FONT COLOR="#000000">>   </</FONT><FONT COLOR="#000080">Subscript</FONT><FONT COLOR="#000000">>   <</FONT><FONT COLOR="#000080">Type</FONT><FONT COLOR="#000000">>data</</FONT><FONT COLOR="#000080">Type</FONT><FONT COLOR="#000000">> </</FONT><FONT COLOR="#000080">SQLMap</FONT><FONT COLOR="#000000">></FONT> <<FONT COLOR="#000080">StreamLocation</FONT><FONT COLOR="#000000">>^demo.AS</</FONT><FONT COLOR="#000080">StreamLocation</FONT><FONT COLOR="#000000">></FONT> <<FONT COLOR="#000080">Type</FONT><FONT COLOR="#000000">>%CacheSQLStorage</</FONT><FONT COLOR="#000080">Type</FONT><FONT COLOR="#000000">></FONT> }

}</FONT>

Result:
USER><FONT COLOR="#0000ff">d </FONT><FONT COLOR="#000080">##class</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008080">demo.A</FONT><FONT COLOR="#000000">).</FONT><FONT COLOR="#0000ff">Fill</FONT><FONT COLOR="#000000">()</FONT>

USER><FONT COLOR="#0000ff">d $SYSTEM</FONT><FONT COLOR="#008080">.SQL</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">Shell</FONT><FONT COLOR="#000000">()</FONT> SQL Command Line Shell

The command prefix is currently set to: <>. Enter q to quit, ? for help. USER>><FONT COLOR="#0000ff">select </FONT><FONT COLOR="#000080">* from </FONT><FONT COLOR="#008000">demo</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#008000">A</FONT>

  1.  select * from demo.A
    

ID P1 P2 1 P1_1 P2_1 2 P1_2 P2_2 3 P1_3 P2_3

3 Rows(s) Affected statement prepare time(s)/globals/lines/disk: 0.1426s/46110/260143/45ms execute time(s)/globals/lines/disk: 0.0004s/16/809/0ms cached query class: %sqlcq.USER.cls12

USER>><FONT COLOR="#0000ff">select </FONT><FONT COLOR="#000080">* from </FONT><FONT COLOR="#008000">demo</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#008000">B</FONT> 2. select * from demo.B

ID P2 1 P2_1 2 P2_2 3 P2_3

3 Rows(s) Affected statement prepare time(s)/globals/lines/disk: 0.0696s/44550/243602/0ms execute time(s)/globals/lines/disk: 0.0002s/4/619/0ms cached query class: %sqlcq.USER.cls13

USER>>quit

USER><FONT COLOR="#0000ff">w </FONT><FONT COLOR="#000080">##class</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#008080">demo.B</FONT><FONT COLOR="#000000">).</FONT><FONT COLOR="#0000ff">%OpenId</FONT><FONT COLOR="#000000">(3).</FONT><FONT COLOR="#0000ff">P2</FONT> P2_3

0
Vitaliy Serdtsev  Jun 9, 2017 to Evgeny Shvarov
Is there any way to "generate" compatible storage? And why SQLStorage? Why not default CachéStorage, but copy-pasted from Class A?
Unfortunately, to use %CacheStorage will not work, since at compile occurs the error:
ERROR #5564: Storage reference: '^demo.AD' used in 'demo.B.cls' is already registered for use by 'demo.A.cls'
  > ERROR #5030: An error occurred while compiling class 'demo.B'
0
Vitaliy Serdtsev  Jun 9, 2017 to Eduard Lebedyuk

Indeed, thank you:

<FONT COLOR="#000080">Class demo.B Extends %Persistent </FONT><FONT COLOR="#000000">[ </FONT><FONT COLOR="#000080">Final </FONT><FONT COLOR="#000000">]
{

</FONT><FONT COLOR="#000080">Parameter </FONT><FONT COLOR="#000000">MANAGEDEXTENT </FONT><FONT COLOR="#000080">As </FONT><FONT COLOR="#000000">INTEGER [ </FONT><FONT COLOR="#000080">Constraint </FONT><FONT COLOR="#000000">= </FONT><FONT COLOR="#800080">"0,1"</FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#000080">Flags </FONT><FONT COLOR="#000000">= ENUM ] = </FONT><FONT COLOR="#000080">0</FONT><FONT COLOR="#000000">;

</FONT><FONT COLOR="#000080">Parameter </FONT><FONT COLOR="#000000">READONLY = </FONT><FONT COLOR="#000080">1</FONT><FONT COLOR="#000000">;

</FONT><FONT COLOR="#000080">Property </FONT><FONT COLOR="#000000">P2;

</FONT><FONT COLOR="#000080">Storage </FONT><FONT COLOR="#000000">Default { <<FONT COLOR="#000080">Data </FONT><FONT COLOR="#800000">name</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"BDefaultData"</FONT><FONT COLOR="#000000">>   <</FONT><FONT COLOR="#000080">Value </FONT><FONT COLOR="#800000">name</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"3"</FONT><FONT COLOR="#000000">>     <</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">>P2</</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">>   </</FONT><FONT COLOR="#000080">Value</FONT><FONT COLOR="#000000">> </</FONT><FONT COLOR="#000080">Data</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">DataLocation</FONT><FONT COLOR="#000000">>^demo.AD</</FONT><FONT COLOR="#000080">DataLocation</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">DefaultData</FONT><FONT COLOR="#000000">>BDefaultData</</FONT><FONT COLOR="#000080">DefaultData</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">IdLocation</FONT><FONT COLOR="#000000">>^demo.AD</</FONT><FONT COLOR="#000080">IdLocation</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">IndexLocation</FONT><FONT COLOR="#000000">>^demo.AI</</FONT><FONT COLOR="#000080">IndexLocation</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">StreamLocation</FONT><FONT COLOR="#000000">>^demo.AS</</FONT><FONT COLOR="#000080">StreamLocation</FONT><FONT COLOR="#000000">> <</FONT><FONT COLOR="#000080">Type</FONT><FONT COLOR="#000000">>%Library.CacheStorage</</FONT><FONT COLOR="#000080">Type</FONT><FONT COLOR="#000000">></FONT> }

}</FONT>

0
Amir Samary  Jun 10, 2017 to Eduard Lebedyuk

You are right Eduard. Column level security would be enough. It is even simpler!

0
Amir Samary · Jun 9, 2017

Hi!

It looks like you are trying to implement security on your class model instead of just configuring it. I think you only need a single class with all the properties. Then you will give user A full access to the table by configuring this user on a Role that gives him INSERT, DELETE, UPDATE, SELECT privileges. 

User B would be assigned to another role that would give it SELECT privilege only.

And if User B can only see a subset of columns from your table, then configure row level security using the Role information on $Role. InterSystems documentation here explains row level security configuration very clearly.

0