So after some digging I realize that there is no built in user level security option for Access 2007. What I need to do is restrict records that users can edit based on who is logged in (they can see all the data but only edit their own). I was thinking that I could make a log in form and assign passwords and go from there, but I was wondering if there was a better method to do this.
For user privileges for read-only, read-write on forms in the database, we implemented following tables, logic.
I created a privilege table along with log-in table. Each screen in the database will have Read-only or Read-write privilege to each user. I inserted all the screen names into privilege table. Another table UserPrivilege will have users and their privileges. Assigning privilege to an user will be done only by Admin user.
A function at start of each form check swhether a specified user is allowed to view or edit form. If he/she is given read-only, we will lock all controls looping thr' controls on the form. Else, nothing to do. OR keep all the controls read-only at design them and unlock them thr' code for write privilege.
The database window is kept hidden when a version to end user is delivered. This prevents usual , simple view to tables in the database, opening forms , reports object in database window. After making mde/accde few more tweaks can be done so that user is not easily able to view tables directly. by-passing startup, special keys etc.
I have been facing this problem too. My solution (which hasn't been broken yet) is to do exactly that. Make a user's table with passwords and a log in form which reads the table for User name, password and user type. I have used two ways to proceed from there: Case statement to open specific navigation forms for that user's functions or a global variable (in a module (enumeration helps)) and an getter function that is checked within each form's open events and changes properties like AllowEdits, and AllowAdditions and even cancel the form opening if it's administrative stuff.
The most important part of this set up is making sure the users are using Access Runtime. If they use the Access version you are developing in they can snoop a little bit and get around this.
Make sure you hide the user's table.
Access runtime can be forced by making a shortcut to the DB and adding /runtime to the end of the shortcut path (with a space).
It's not perfect, but it works for my purposes and It might work for your's.
I did dot this in 2010, but 2007 should be pretty much the same.
Assigning username/passwords in Access (especially with an access back end) has a number of critical issues that are worth pointing out. Firstly, if you don't encrypt your DB, then any of your users who are savvy enough to go looking for it will be able to find it, and therefore get full access to it. If you encrypt the DB, if anyone can get access to your source code you're toast, since they will be able to see the DB user/passwords stored in the code. This issue persists if you use other SQL db's, but at least in those cases you can restrict the user supplied to the Access .accdb file to have certain permissions.
For my case, I have 3 levels of security. Firstly, I heavily restrict what I send out to make it very difficult to access the source code, which you kind of have to do no matter what. Secondly, I distribute different levels of access with different DB passwords (I'm using a MySQL back-end, you could do the same with a SQLServer back-end, but with Jet you're out of luck), so even if users could see the DB user and password, they are limited in what they can do. Thirdly, since I deploy on a corporate network, I take advantage of windows groups, and use those to filter out what is visible to different users. That way, users can only use the forms if they are authenticated onto our network. If the file discovers it's not on the network, it deletes itself and terminates.
Function IsMember(strDomain As String, strGroup _
As String, strMember As String) As Boolean
Dim grp As Object
Dim strpath As String
strpath = "WinNT://" & strDomain & "/"
Set grp = GetObject(strpath & strGroup & ",group")
IsMember = grp.IsMember(strpath & strMember)
End Function
Function GetCurrentUser() As String
GetCurrentUser = VBA.Environ$("USERNAME")
End Function
Function GetCurrentDomain() As String
GetCurrentDomain = VBA.Environ$("USERDOMAIN")
End Function
Related
Working in Nintex, I have a workflow that is kicked off when a form is saved. The workflow generates a PDF version of the Nintex form (we need actual signatures - digital in the future, fingers crossed). This is done by updating a word template, then converting to PDF.
When the word document is updated, the 'assigned to:' field is getting an AD account name instead of the user's First, Last name (which is expected). Now I'm trying to format it so it's more appropriate to the Hard Copy (in the Nintex form, it shows as Last, First).
I used a Query User Profile action, passed it the same variable I was using to hold the form's 'assigned to' value, and then used the drop down menu to choose the user profile variables I wanted (First, Last, also: username, account name, Distinguish name). All values are generating empty strings.
I've incrementally tried handing the values to variables that are of type String, Person, or Collection. I also handed it my username instead of the variable and set my account info for the login. I've always selected values, so I don't think it's a typo.
I'm at a loss... the workflow emails the user at the end, so it's getting the data. I hope that's enough info, I'm new to SP/Nintex so it could be a rookie mistake. Any help is appreciated.
Thank you!
I've seen issues where the User Profile Service properties have not been configured adequately, which leads to a lot of empty variables when running an LDAP Query action for AD attributes.
If this is the case, then one approach is to get the Farm admin (if you don't have access) to take a look at Manage User Profiles in Central Admin and see what AD attributes are mapped to the user profile. If mappings are changed you'll need to run a full sync to bring over the values. It can be inconsistent in my experience as well.
I have searched for current solutions, but can't find a set of guidelines or examples as to how to achieve the following:
The original requirements involved models with required fields, so we included annotations to those fields. As usual, there is a last-minute change and we are being asked to allow the users to save drafts. These drafts must allow the user to save the forms without any of the required fields.
I would like to know what the best practices for this problem are.
Solutions I am considering, but I accept they might be a hack (and that's why I am asking the experts)
If the user clicks "Save as Draft" I can capture the fields that have information in another ActionResult and run basic validation on those fields. Since there is a chance that required fields are missing, I am thinking in storing the captured info in a temporal model (without any required annotations). If the user decides to edit such form, I can populate fields in the view with the temp. model until the user clicks on "Submit"
Another option is to remove all required annotations and run client-side validations... but am wondering on the amount of work required to do so.
Any thoughts are very much appreciated.
Just have 2 save methods. 1 which is called from the autosave and 1 that is used to submit the process. In the autosave method do not check if(ModelState.IsValid).
Whether you choose to save the incomplete objects to the same table or a different table is your choice. In a relational world I would likely use a separate table, in a non-relational world I would use a singular object collection.
This will allow you to keep the same set of original models. There is a very high cost to duplicating your models, there are certainly times that warrants pass by value/copy but make sure the cost of mapping is there. In this situtation I do not believe there is value in mapping, except perhaps at the persistence level if you need to map to a different object because of an ORM's constraints.
There is deep value in these partial forms. Recording this on the server will allow you to apply analytics to learn why your users abandon your processes. It also gives you the ability to follow up on users who leave incomplete forms such as sending a reminder (nag) email.
You don't want to save anything to your database until it is complete. Having a duplicate table where everything is nullable is cludgy as hell. Before HTML5, the typical path was to save the information to the session, which you could then pull from to refill the fields, but that's requires having a session with a relatively high expiry to be useful.
Thankfully, HTML5 has local storage, which is really the best way to handle this now. You just watch for onchange events on your fields and then insert that value into local storage. If the user submits the form successfully, you destroy the local storage values. Otherwise, you attempt to read those values from local storage when the page loads and refill the fields.
See: http://diveintohtml5.info/storage.html
There's pretty broad support, so unless you need to worry about IE6 or IE7, you won't have any issues.
Another option (depending on your data obviously) would be to comply with the database but not the model. By this I mean ignore Model.isValid and disable Javascript validation on the front end but then satisfy the database table. In a form, you mostly have:
textboxes - default to "" or " "
checkboxes - easy true/false default
radio buttons - one is probably already selected
dates - default to DateTime.MinValue (or DateTimeUTC)
enums - default to 0 (usually for 'unspecified')
Hopefully you are also saving a flag designating that it is in Draft state so that you know you need to interpret the 'null codes' you have set when it comes to displaying the semi-populated form again.
I'm programming a new application with many users, a few roles and specific permissions for those roles. For that I want to create the following tables:
Users (ID,Login, password,..)
Roles(ID,Rolename)
User_Roles(User_ID, Role_ID)
Permissions(ID,PermissionName)
Permission_Roles(Permission_ID, Role_ID)
My idea was to build a function, which allows to check if a user has a specific permission to access a form. I would do that by creating Permissions/Rules like 'canReadFormX', 'canEditFormX' which would allow me to use one main function to check and perfom those specific rules and a function per form to call it.
Is that a way to go (or rather did I understand everything correctly regarding RBAC) or is that just far to complicated? Any advise is very appreciated!
It seems fair to me, and similar to what we have already set, for the first 3 tables.
You then have to solve the 'action' problem, ie to distribute permissions to use your appl's actions. I am not sure that your 'Permissions' proposal will cover all the situations, as you have to deal with 2 major categories of actions:
The 'Open form' actions, that you already have identified: you effectively have to define 2 levels of authorisation for each form: the 'view' right, and the 'update' right.
All other actions, such as form specific buttons or menus, that will allow you to run a specific action other than just opening a form (execute a report, make a specific calculation, automatically import or update data, etc).
One solution/My advice is to maintain 2 tables for this:
A 'Forms' table
An 'Actions' table
And the corresponding link tables:
A 'Form_Role' table
An 'Action_Role' table
With such a configuration, you are fully covered. You can even decide which role has the right to see a specific report on a specific form, as long as the corresponding action is accessed through a specific control or menu on the form.
Both Forms and Actions tables are very interesting as they both participate in your application metamodel...
EDIT: By the way, if you are on a domain, you can use user's domain credentials to control his\her access rights to your system. In this case you do not need to store a password in your RBAC system.
In Lotus Notes hidden client, hidden views are not shown by default but you can further hide them by using outlines.
But a user can gain access to hidden views by following either of the following
Right click on the database bookmark, "Application" -> "Go To" while holding CTRL+SHIFT
User opens database and goes to "View" menu and click on "Go To" while holding CTRL+SHIFT
In these scenarios users can see any hidden views or views which are only hidden on the outline.
Is there any way to hide those views aside from creating a reader list for each view?
Assuming that you do not require the documents in the view to be hidden. Ben's response is quite good. But I am not a big fan of Reader lists in view designs, even if you're using ACL roles to manage them. Reader view lists are notoriously hard to maintain, and easily overlooked later when debugging user issues.
If you want to prevent UI access to the view but still permit the user access to the documents via the application programmatically, you will need to goto the view's "QueryOpen" event in the Domino Designer and insert the the following code.
Sub Queryopen(Source As Notesuiview, Continue As Variant)
messageBox "Not authorised to access this view"
Continue = false
End Sub
This should prevent a user opening the view via the UI as you described, but allow the application to use it where required. And if so desired later on, you can programmatically control when those views can be access by the UI. I have had a couple of instances where I have had to create control objects that determine which type of user can open/paste documents into a view.
My answer is on the basis you just want to prevent people accessing views. But if you need to actually hide the documents in the view, then you need to consider document level security, and then design your application around that. Admittedly, this will increase the complexity of the application because, if required, you'll need to use agents to run on someone else's behalf in order to act on the documents the user can't see.
Unfortunately, there is not. The only true way to secure anything in Lotus Notes is via the reader lists at the document level, or access control lists at the database or server level. VIews, Forms, etc are just design "documents", so they need to have reader lists applied.
Those other tricks usually suffice if there isn't highly sensitive data. Many users don't figure out that means of displaying hidden views, but of course once they do it's all over :)
Even if you protect your views, any user with at least reader access can make user defined view with all documents. So I think this attempt is silly - don't waste your time.
I have a Lotus Domino server with a truly astounding number of Domino databases on it, arranged in various folders.
Is there some means of exporting a list of all these databases, with their titles and creators' names, in a spreadsheet format of some kind? I have the Domino Admin and Domino Designer software, and I have or can get whatever access rights I'd need.
Actually, you can use a very simple Lotuscript agent to connect to a server and walk through all databases on the server, using the NotesDbDirectory class. Here is some code, modified slightly from what's in the 6.5 Help files - this dumps the title and path of all databases to a csv file. Note: the one argument to the GetFirstDatabase method let's you specify which objects on the server you want to scan - 1247 is the constant for "Databases" - basically, all NSF files. There are other constants for finding templates only (NTF's), only database with replication enabled, etc.
Sub Initialize
Dim db As NotesDatabase
Dim f As Integer
f = Freefile
Open "c:\dbExport.csv" For Output As #f
Dim dbdir As New NotesDbDirectory("") ' opens LOCAL - put a server name here
Set db = dbdir.GetFirstDatabase(1247) ' all databases - NSF, NSG and NSH (no templates)
While Not(db Is Nothing)
Print #f, """" + db.Title + """, """ + db.FileName + """"
Set db = dbdir.GetNextDatabase
Wend
Close #f
End Sub
You'd think there'd be a way in the Domino Admin, but there's no way to export the list. So, your best bet I think is to use the Domain Catalog database. To build it, go into the server configuration doc > Server Tasks > and turn on the Domain Catalog. Then the catalog.nsf database will be built and will contain all the databases in your domain. You can customize the views to include the information you need.
Then finally, you can go into a view, select all the documents and click Edit > Copy Selected As Table. Then paste that into a spreadsheet.
It is a little known fact that you can "select all" in the Admin client and paste into Excel. There is also an option for a flat view of databases instead of a folder view.
The creator of the database is not listed but there is a lot of other useful information
Inherited some legacy server, didn't we ?
If the server was sensibly maintained in the past, you already have the following things :
a catalog.nsf database, which is exactly what you want, only better
the catalog server task up and running.
The catalog task is the task that automatically builds and maintain the catalog.nsf database. If it is not already running, you can launch it once at teh server console in Domino admin :
load catalog
and even better, add it to the server tasks in the server's notes.ini
Now, the catalog tasks only cover the databases whose properties have been set such as to allow cataloging. A well behaved Domino admin would not allow a database to reach production without those properties properly set (and I believe it is the default anyway) but it seems you are not exactly in a nominal situation.
If this is not enough and if you have time to tinker around, I was in a similar situation once, and I built a database with some rather advanced scripts to conduct a thourough census, including agents and their schedules etc. If you want, I'd be happy to pass it to you.
Have fun with your new toy !