I want to add a form of access security to a DLL that I created and I was hoping to restrict within the code a check of the calling application's GUID. I cannot seem to find a way to retrieve the calling app's GUID to verify if it has access.
Is this even possible, and if so could someone provide a code snippet on how to determine the GUID?
I found my answer...here is an example in VB:
Dim asm As Assembly = Assembly.GetExecutingAssembly()
Dim attribs = (asm.GetCustomAttributes(GetType(GuidAttribute), True))
MsgBox(DirectCast(attribs(0), GuidAttribute).Value.ToUpper)
This provides the calling application's GUID.
Related
Scenario:
My company has a legacy (read that as 32 bit) windows form application that will be around for quite some time in the future. This application uses an embedded web browser control that is supplied pages that are contained within the database that it maintains. It was built like this so we could extend/modify as needed. I say this so that I can validate that security is not a concern. Only the application and developers with the correct tools have access to the pages or database. The application is only available inside the office.
There are some processes that I need to accomplish using ActiveX objects that are embedded within the pages/application. One of the biggest and most annoying thing that happens is the ActiveX security warning when I got to create instances of things like “scripting.filesystemobject”. Example:
Set oFSO = CreateObject("Scripting.FileSystemObject")
My solution is to create a DLL that is installed locally on each machine that needs access to the extended functions, have the all the functions (whole DLL ??) marked as safe so that the web browser control does not present the security warning. I have been searching using google and came across very few examples, and all of which are in C# which is not my strongest language.
I’ve had to convert from C to Vb.Net visual basic to get what I have now. When I go to register my DLL, I get the following error message:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319>regasm
Z:\VBNet2017\APIInternal\APIInternal\bin\Debug\APIinternal.dll /tlb
Microsoft .NET Framework Assembly Registration Utility version 4.8.4084.0
for Microsoft .NET Framework version 4.8.4084.0
Copyright (C) Microsoft Corporation. All rights reserved.
Types registered successfully
RegAsm : error RA0000 : Type 'APIInternal.API.Accupay' has an invalid default COM
interface: 'APIInternal.API.Accupay'
UPDATE: Thank you Hans; the error is gone. I've also made some changes in the source code; I changed the ProgID to something that closely resembles where and what this is for. I'm still having issues in creating the object in VB Script.
This is the output from the current version of the code. This is the code, stripped down for clarity:
Option Strict On
Imports System.Runtime.InteropServices
Imports System.IO
Namespace API
Public Interface IAccupay
<DispId(1)>
Function GetFiles(ByVal Folder As String) As List(Of String)
End Interface
<Guid("8B4B5CEF-8B3A-49A1-9053-E909F82D9E73"),
ProgId("AddIn.Accupay"), ClassInterface(ClassInterfaceType.None),
ComDefaultInterface(GetType(IAccupay)), ComVisible(True)>
Public Class Accupay
Implements IAccupay
Private Function GetFiles(Folder As String) As List(Of String) Implements IAccupay.GetFiles
Return Directory.GetFiles(Folder).ToList
End Function
End Class
I have tried just about every combination of ProgID, Name space, Interface name and class name to get this error to go away without any luck. I do know there are other elements that need to be addressed or added, such as error trapping and, if I’m not mistaken, how to actually implement the ObjectSafetyOption which I still don’t know how to do.
I have been using the Guide at the bottom of this article:
Is it possible to mark an ActiveX object as safe so that IE settings need not be changed?, the second answer, but I haven’t had any success.
Please, can someone point me in the right direction, maybe show me what’s wrong with the code that I have and how to physically implement the ObjectSafteyOption that is needed for the web control. Links, additional reading, code examples or comments on how to get this fixed and working would really be appreciated.
Thank you for reading and any help you send my way, Fred
PS: If you need more information, or have a better solution, please don’t hesitate to reply or comment.
UPDATE:
With the code that I have now, I am able to access the DLL in VB.Net visual basic:
Imports System
Imports APIInternal.API
Module Program
Sub Main(args As String())
Dim API As New Accupay
Dim FileList = API.GetFiles("C:\Windows\")
For Each Item As String In FileList
Console.WriteLine(Item)
Next
End Sub
End Module
However, I still can't seem to get the correct calling for a VB Script/html page:
Set Test = CreateObject("Test.Accupay")
Which returns the VB Script error "ActiveX Component can't create object: Test.Accupay or any other iteration of the parts of the name that I tried. I think part of this is that I don't understand how the creation of the project leads to the creation of the object in a com base environment like VB Script.
Fred
The answer to this problem is two fold: You must target the correct platform (X86) AND use the 32 bit version of regasm. Once I realized this was the issue, I was able to create the DLL and use it's functions in the Web Browser control without the active X warning. One example is I can now open the default browser (in this case, NOT IE/EDGE) from a link within the WB Control and another is to get the contents of a folder for further processing within the WB page.
We have a number of classic ASP websites using a VB6 DLL (COM) object for their functionality in the standard way. The DLL is regsvr32'd and the pages use Server.CreateObject to create an instance of the necessary object in the DLL, which in turn triggers the OnStartPage function of the object being created, passing in the ScriptingContext which we then use to get Request (querystring, form) information, read/update session information and read/write cookie information (etc). For clarification, the way you update/store a cookie value using ScriptingContext is
objSC.Response.Cookies(Key) = Value
In preperation of doing a complete .Net overhaul on the code base (and as a first step), we ran the code through the .Net 2008 VB upgrade tool, which makes a few minor code changes, sets up references to interop libraries (for ADODB, ASPTypeLibrary, CDO, etc) and adds the necessary attributes to allow the .Net object to be exposed to COM, and after a few tweaks here and there guided by comments (todos) left by the upgrade tool, the code is compilable except for anything that tried to update/store a cookie using the above code as now, through the ASPTypeLibrary (Interop), the Response.Cookies collection is readonly (with no obvious way to write a cookie now).
If I comment out the offending line of code, the code compiles, and all I need to do is register this new .Net DLL (and it's interop DLLs) in the GAC, use regasm to register it through COM and the classic ASP sites continue working as if nothing happened (except for writing cookies), using Server.CreateObject to create what it thinks is a COM object, triggering the call to OnStartPage, passing in the ScriptingContext.
So although the code base is "upgraded" to .Net it is using a lot of interop libraries to continues working as before, including using the ASPTypeLibrary.ScriptingContext object, as this is what the classic ASP pipeline exposes.
Does anyone know how to write/store a cookie in this scenario?
Need to convert cookie item to IWriteCookie interface. Then it will be writable.
Imports ASPTypeLibrary
Public Class Test
Private oContext As ASPTypeLibrary.ScriptingContext
Private oResponse As ASPTypeLibrary.Response
Public Sub OnStartPage(e As ScriptingContext)
oContext = e
oResponse = oContext.Response
With CType(oResponse.Cookies("fromdotnet"), IWriteCookie)
.Item = String.Format("hello from .Net : {0}", Date.UtcNow())
'.Domain = ""
'.Path = "/"
'.Secure = False
End With
End Sub
End Class
You may want to check out other interfaces such as IReadCookie, IStringList, IRequestDictionary etc.
With note that:
Full trust for the immediate caller. This member cannot be used by partially trusted code.
there is another option : ContextUtil.GetNamedProperty Method
System.EnterpriseServices.ContextUtil.GetNamedProperty("Response").Cookies("fromdotnet") = "hello"
The user clicks a button, a new form is generated where the user enters his/her password? How can I keep an in-memory copy of the username?
For instance in web forms, I can just use Session ("User"). How can I replicate this with winforms?
Thanks
You could use a static (Shared in VB .NET) object
Example
Public Class SessionInformation
Public Shared Property UserPassword As String
End Class
You can then access this by calling
SessionInformation.UserPassword
Since there seems to be some concerns revolving around whether or not this is a valid implementation I will explain why this is not the best idea.
This creates a single instance of SessionInformation which means that if it is changed anywhere in the program it affects the rest of the program.
Maintaining object persistence can be difficult if you aren't using a database (SQL, Access, a file, etc...) to maintain an out of memory copy of the object that you want to retrieve at a later date. The easiest way to implement this would be to use a SQLCE database that live in your application folder and using standard T-SQL to store the information that you need. However in the case of a password this may be non-ideal due to security issues.
Or the better way for logging in and out user would be to make use of the System.Security.Principal Namespace to create a user for your application.
You don’t need an equivalent to the Session object in web applications. Sessions are only needed because web applications actually have to access variables across process boundaries (= a session in a web application encompasses multiple requests of a user to a web server, and historically each request started a new application!).
In a “normal” application, this isn’t the case – any non-local variable will do. In your particular case, it would make sense for the password form to have a property that contains the username. The user then enters their username and password and the caller of this password form can retrieve the username:
' The caller looks something like this:
Dim pw As New PasswordForm()
pw.ShowDialog() ' Display the dialog, and wait until the user has dismissed it.
Dim theUsername = pw.Username
Inside the PasswordForm, there is something like this:
Public ReadOnly Property Username() As String
Get
' Return the value of the username textbox field.
Return UsernameInput.Text
End Get
End Property
We could get more sophisticated but this will do.
If you need to reuse the username across the application, chances are that you also need to share other information about the user (what are they working on? …). This, in short, is the state of the application and there is usually an object which represents that state. This would be the right place to store the username as well.
If your application only has one other form (the “main dialog”), then just use a private variable inside that form to store the username. No need for a global variable.
Just have a public variable on the forms, never unload the form, and get the data from that form using formname.variablename (define it as public at form level).
This even can be achieved with controls if you set them to public.
BEFORE THE FLAMES: this solves OP problems, whenever if this is optimal, good or anything else, is another problem.
I'm using Silverlight 4 OOB & elevated trust.
I need to get all the filenames on specific directory & populate an object List(Of String)
The compiler throws an error "Method not found" on .Getfiles() method.
Dim files() As String = System.IO.Directory.Getfiles(Path) 'this line is failing..
Help!
The GetFiles is marked as "Security Critical" and therefore cannot be used from your code.
You will want to use the EnumerateFiles method instead. GetFiles is sooo .NET 1.0, EnumerateFiles is much slicker, even in the full framework you'd want avoid this older Array returning API if you can.
As far as I know you cannot directly access the whole hard drive using Silverlight OOB.
Quoting from Silverlight site:
When running in a trusted environment, you can access only files in
user folders, specifically the MyDocuments, MyMusic, MyPictures, and
MyVideos folders. Although this makes sense from a security point of
view, it’s limiting. You want to enable the user to drag their data
from any location. As it stands right now, if you try to drop a file
from a location other than stated above, Silverlight will throw a
security error.
Please refer to this link for details on how to work with the hard drive using Silverlight OOB:
http://www.silverlight.net/learn/overview/out-of-browser-applications/advanced-silverlight-out-of-browser-introduction#Exercise3
When accessing Silverlight in WCF you get proxies generated with ObservableCollection
Thats fine when you're databinding, but a little clumsy when you're just calling a method. For instance the following service method :
[OperationContract]
public SearchOrdersMsgOut SearchOrders(ShippingStatusType[] shippingStatuses,
string[] orderId)
{
}
gets generated with ObservableCollection. What! They're just parameters. Why would I ever want to 'observe' them?
I'm fine if I have to do this - but it seems like there should be a way to force simple array structures when I know I'm never databinding - especially on input messages.
I'd much rather do this :
searchCriteria.PaymentStatus = new [] { PaymentStatusType.PaymentFailed, PaymentStatusType.Unpaid };
than this :
searchCriteria.PaymentStatus = new ObservableCollection<PaymentStatusType> { PaymentStatusType.PaymentFailed, PaymentStatusType.Unpaid };
Is there a way?
PS. I do actually use a SearchCriteria object for my search criteria - but I simplified for this example wondering if parameters were handled differently.
You can do this service-wide, but not on a per-method basis. In the Add Service Reference dialog box, click on "Advanced", and choose "System.Array" for the Collection type. But I'm not aware of any way to do it method-by-method, i.e., use array for some methods and ObservableCollection for others.
OK here's a bizarre twist after having got used to using ObservableCollection for my silverlight clients.
I tried to return a Linq2XSD object from my WCF service - and then suddenly low and behold it changed all the ObservableCollection<T> properties into simple arrays [].
I thought it was something specific to Linq2XSD - so I tried just adding a simple XTypedElement property to the service definition:
public XTypedElement[] PipelineLogs { get; set; }
This triggers [] instead of ObservableCollection<T> in the generated proxy - where normally string[] would become ObservableCollection<string>.
Don't ask me why!
I've since removed it because I actually prefer ObservableCollection<T>. I just thought the observation might interest someone with a similar problem - especially if anyone can explain why its doing it!
Ended having the OPPOSITE problem when VS2010 RC had a bug preventing it from generating ObservableCollections.
Fortunately there are two workarounds:
Option 1:
Believe the best option – this is to update the “Reference.svcmap” file for the impacted service reference. In Solution Explorer, select “show all files” and expand the impacted reference node. There you will find the “Reference.svcmap” file, double click to open into the editor. For the observablecollection mapping, you should see currently something like this:
<CollectionMapping TypeName="System.Collections.ObjectModel.ObservableCollection`1" Category="List" />
Change TypeName value to include the Silverlight assembly “System.Windows” – like below :
<CollectionMapping TypeName="System.Collections.ObjectModel.ObservableCollection`1, System.Windows" Category="List" />
Option 2: Generate your
Reference.vb/.cs service reference
proxy code files outside of VS by
using directly SLSvcUtil.exe. Example
of running the tool via command-line
where it will address the
observablecollection issue code
generation issue: "C:\Program Files
(x86)\Microsoft
SDKs\Silverlight\v3.0\Tools\SlSvcUtil.exe”
/r:"C:\Program Files (x86)\Microsoft
Silverlight\3.0.40818.0\System.Windows.dll"
/ct:System.Collections.ObjectModel.ObservableCollection`1
http:///Service1.svc
This will by default generate a C#
version of your service reference
proxy code. If you need to generate a
VB version, you can pass a
“/Language:VB” switch.
Another thing to check (if you want ObservableCollection<T> but you're getting T[]) - is the Reference.svcmap file
Make sure that you have included 'System.Windows' in the typename.
<CollectionMapping TypeName="System.Collections.ObjectModel.ObservableCollection`1, System.Windows" Category="List" />
and not
<CollectionMapping TypeName="System.Collections.ObjectModel.ObservableCollection`1" Category="List" />
I'm guessing perhaps it can't find the Dll and defaults to []