How to store user-specific data in SharePoint - sharepoint

I have some user-specific data that I need to store in SharePoint and make accessible to the user through custom webparts. Let's say a list of favorite URLs. What would be the most straightforward way to store this information?
Some builtin propertybag for SPUser or similar that I'm not aware of.
SPList, associated through User column.
Custom database table, associated through SPUser ID.
Otherwise?
Sounds like a RTFM to me, but I'm probably asking google the wrong questions.
[Update]
We eventually stored this information in a simple list, in a fixed location, with a Person field to filter on. Perhaps the simplest solution indeed, but technically I think the marked answer below is nicer.

If you want to make them reusable across the site collection for each user you can add Fields to the User Information List. You can add a feature receiver to your web parts solution that can create this column or check to see if this column exists in the User information list to be sure that the Column exists.
The User Information list is a Standard SharePoint list that SharePoint uses to store user information.
To access the User Information List you can go to the Root web of the Site Collection and use the SiteUserInfoList property
E.G.
SPList userInformationlist = SPContext.Current.Site.RootWeb.SiteUserInfoList;
//Or
SPWeb web = SPContext.Current.Site.RootWeb;
SPList userInformationlist = web.SiteUserInfoList;
To access a users List Item you can use the Users Id to get the ListItem back from the User Information List
E.G.
SPListItem currentUserItem = userInformationlist.GetItemById(web.CurrentUser.ID);
If you are using MOSS you can store this information in the User Profiles and make it available across Site Collections this does not need My Sites to be enabled. You would need to use the User Profile classes to access this.

I would go for the properties on the user profiles. You do not want to store the information on the root web as it is not information regarding the root web.
Your example with the favorite urls, each user has a "quick links" collection on their profile. An ideal place for storing urls for each user. :)

Build a webpart that reads/writes a custom database and you'll have the flexibility to use the webpart across SiteCollections, WebApps, or even seperate Farms.
This was implemented where I work and it has been a big success. We needed a way to provide our end users a large selection of important, commonly used links. End users have the ability to display the links that are useful for their particular job function and have a webpart that can be put anywhere to reference those links that are important to them. You also have the ability for an “admin” to go to the custom database and update any URL’s that might change without the end user ever being impacted or ending up with a broken link.

This is a very good question.
Although I have no perfect answer, here are some things you can consider:
Store data in a browser cookie if this is feasible.
Store in the Site collection's rootweb in the Properties, keyed by the user's login ID. You may want to elevate when reading / writing the properties just in case the user has access to a subweb, but not the rootweb.

Related

What is the best way to prevent access to the nsf through the notes client when developing xPages applications

When developing xPages applications, what is the best practice for securing the nsf from a traditional Notes client. I would like to prevent any access to the database through the Notes client while having no impact to the xPage.
I would like to restrict access for a number of reasons. Security to the documents and the views, preventing users from using the application in notes and forcing them to use xPages. It looks like there is no silver bullet to accomplish this, but rather I need to use a number of different solutions.
You can't prevent it by ACL. You can redirect common users to open your application in browser, tho. In our applications, to prevent opening them in client and XPiNC, I have made simple subform with queryOpen script:
Dim ws as New NotesUIWorkspace
ws.URLOpen Source.Document.HttpUrl
Continue = False
This subform is put inside forms that user can get doclinks to or open from view. At view level you can adopt similar approach for all visible views and/or OpenDatabase script.
This works very well with this tweak: native Domino links and XPages
Why do you want to prevent access?
I assume that administrators and servers should be able to access the nsf. So LocalDomainAdmins, LocalDomainServers, etc. should be part of the ACL.
You can restrict user access from the Notes client to the nsf itself by making sure that user access groups in the ACL contain the names of user accounts (person documents in names.nsf) that have no matching Notes name (Notes id). The users can then only access the application from web and not from Notes.
But this might not be a feasible solution if users already have Notes access. Because then you have to create new person documents with user names that does not match the existing person documents, meaning that existing users then have a person document for Notes access and a person document for web access.
Instead you should perhaps look at restricting access to documents (using Readers fields) and views (through restricting access to a certain role).
I'd consider going even simpler on this and simply changing the launch property for the client to redirect to a page that indicates the user should access the application through a browser, and provide the URL to access the system. This isn't a perfect solution, depending on how information is disseminated in this system, but if users are simply opening the application through the notes client this would provide a good redirect as well as retraining the end user how the application is meant to be used in the future.
Split the app into two .nsfs. One for data other for only xpage design. Lock down the data .nsf and restrict it to only allow design signer access. It will cause some headaches as you will need to use sessionAsSigner to pull data.
Create a new role in the database called "Admin"
Put code in database script post open event that will use uidatabase.close if user do not have the admin role
Put script in alla views "query open" events with continue = false for all users without the admin role. ( this will prevent user from opening a view from the workspace using the go to view menu action)
Assign the "Admin" role in the acl only to the people that should be able to access it from the Notes client
You can also "hide" all views from Notes for everyone except the "Admin" role, but this might cause other problems depending on how the application is designed.
By either stripping the fields from the Forms or hiding all of them, you can make attempting to access the data in Notes unpalatable. You could then hide the views from the Notes client and make accessing the documents even more difficult (though someone could still create private views).
In one of our databases, the database opens to an XPage in XPiNC, which displays a link only for administrators to open the views.
var server:NotesName = session.createName(#Subset ( #DbName(), 1));
var filepath = database.getFilePath();
return "Notes://" + server.getCommon() + "/" + filepath + "/ViewToOpen?OpenView";
While it doesn't prevent the end user from accessing the Notes client version in all circumstances (someone could still send a doclink or view link), it allows users to follow their normal double-click pattern and open the database the way I want them to see it. With the link, I can allow such for those who really need Notes client access to it.
Maybe a bit late to the party, but here is our solution, to be put into the DatabaseScript PostOpen event.
#If(
#IsNotMember("[Admin]"; #UserRoles);
#Do(
httphostname := #DbLookup("" : "NoCache"; #ServerName : "names.nsf"; "($ServersLookup)"; #ServerName; "HTTP_HostName"; [FailSilent]);
#URLOpen("https://" + httphostname + "/" + #WebDbName);
#Command([FileCloseWindow])
);
""
)
This checks for the [Admin] role (to grant administrators backend access, could be left out if not needed) and if the user is not a member, gets the configured server hostname from the Domino server's addressbook, then builds and opens the URL in the browser, and finally closes the database.
Other than LotusScript in the PostOpen event, this #Formula code is capable of closing the database. And with this, you have all the code in one place only, and it gets triggered regardless if the user enters the db using a document or a view link or just opens the database via tile.

I want only managers to acces a hidden view Lotus Notes 9

How can I let only managers to acces a certain view, what do i need to write in the PostOpen of the view(lotusscript),
TY very much guys
AFAIK there is a "Security Tab" in the view design editor where you can specify who (person,roles) can use the view. No script necessary. The view will be hidden for persons that is not allow to access the view.
As you are not describing in your question, why you want to hide the view, here are a view general comments:
Hiding a view from a group of people does not limit access to certain documents to this group of people. Unless the documents are otherwise protected, users can create private views and folders that display the documents shown in the restricted view. If you do not want to grant them access to the documents, please use reader fields.
"Managers" in the ACL have the right to change the database ACL, ... In regards to read access to documents, there is no difference to "Reader"s, as long as you are not using Reader fields in documents.
If you meant "Managers" as a role, please follow Peter's and Knuth's advice but keep in mind once more that limiting access to a view does not limit access to the documents via another view.
For more details on access rights, ... please take a look at Access levels in the ACL, Roles in the ACL, Creating read access lists to limit view and folder access and The Domino security model.

Managing the accessabiliy of data item in a web app

I am about to start a new project with Flask+AngularJS, first time experience with such mix. But my questions are not related to my choice of platform/framework.
There would be loads of situations where some lists of items are presented to user, and user can click on one of the items to browse it. Naturally, such functionality would be provided by passing to the client a list of item database ids, and browsing would happen by requesting item info by its id. However, I am uneasy about enabling user retrieving some information by its it. There could be cases when a user is not entitled to open certain item.
So, I have two questions:
Is it good idea to share database object ids to the client? It's definitely easier, but doesn't it reveal too much info for a malicious logged-in user? An alternative could be generating a unique ID for every clickable item, and keeping at the server side a dictionary what those ids mean. Feels like pretty big hassle (not to mention extra processing overhead), but maybe it's worth the pain?
If I'd go with revealing the item database ids to the client, then I should still keep a list of the items that were shown to the client (in this session), and let the user browse only those. Thus, any attempt to browse an item by entering its id directly in URL (or POST request) would be stopped, if the user "had no legal way to access it". Is there any name for this technique, so I could read on the best practices how to implement it?

External login options for Sharepoint?

We have a Sharepoint Project Management site up and is active amongst our clients. The site url looks like this:
https://projects.acme.com/clients/[client_name]
Each of our clients has to remember (or bookmark) this long url; the users of this site are not very savvy. They fumble with it all the time. We also do not want clients to know who each other are; so client 1 shouldn't know that client 2 is a client.
We would like to put a login form on our website, prompting for user id and password. Then we would like to be able to route the user based on a successful authentication, to the specific web that is theirs.
Is there a good clean way to make this happen? Is forms authentication the way to go? Are there drawbacks to using forms authentication?
Given my url structure, would this approach work?
http://msdn.microsoft.com/en-us/library/bb975136(v=office.12).aspx
Update: I'm not particularly interested in a solution that requires two weeks of effort on the part of a programmer/admin to setup, nor am I particularly interested in one of the commercial solutions that are $4k-8k. I was hoping to discover a pretty straightforward way to get this done in under a day of effort.
Yes, you can implement it using FBA.
However, if you use only the user ID and the password, the user IDs across all websites will need to be unique (i.e. if client 1 creates a john.smith user ID, client 2 will have to use john-smith or johnsmith or something completely different). The easy solution is to ask additionally for the company name on the login form, the user ID and the password, but then you'll probably have to handle different ways the users will enter the company name (i.e. acme, ACME, Acme, Acme Ltd, Acme Inc, Acme Inc.).
Update:
You can also consider host-named site collections and have URLs like https://client_name.acme.com. The downside is that you cannot use Central Administration to create a host-named site collection - you can do it by using PowerShell or custom code.
Generally it is highly unlikely you will find a free solution to get your task done in under a day of effort - admittedly, SharePoint does support FBA, but does not provide basic things like a login form, a change password form or user management; you need to create them yourself or use some existing solution (e.g. SharePoint 2010 FBA Pack).
If you want to separate users and also make URL's more sweet you have a two ways.
Create a web applications per user.
Create one application with multi tenancy support. Check more on this Spence's Harbar article.
Second approach is more flexible, but harder to implement, and if you plan to have many clients (more than 50) it's the only way.

persist values/variables from page to page

I'm wondering if there's another solution to my problem, that's considered more the Sharepoint way. FIrstly, my site is an Internet site, not Intranet. The problem is, all I'm trying to do is save values/variables from page to page in Sharepoint. I know the issue with Session Variables, but this seems to be the only way I can see to accomplish this. I know there are webparts that can store this value, but am I wrong in thinking this won't be persisted from page to page?
Basically, I'll be extending the Content Query Web Part to dynamically filter it's results based off of a variable/value. The user chooses their 'area' from a dropdown, and the CQWP in the site will change and query results based off of this value (It will be a provincial structure as it is a Canadian site, so if someone chooses the province 'Ontario', this value is saved in a global variable, and these extended CQWP that are throughout the site, will get this value, and query lists flagged as Ontario).
Is Session variables the only solution?
Thanks everyone!
Session variables are not the only solution. You can use Browser Cookies as well.
Not necessarily the 'SharePoint Way', but it is an option.
The SharePoint way would probably be to use something in the user profile, although of course that's not as appropriate for an anonymous site. Don't worry too much about going outside the SharePoint way of doing things - with an internet site it's pretty much unavoidable.
I'd recommend a cookie rather than a session variable if you only need to store the one value - simple to use from either client or server code, and none of the potential storage issues you get with the session.
You can always use database to persist this kind of data. Not mentinoning problems with sessions in SharePoint farm scenario.
You can read or write or remove persist key/values in web or webapplication level, take a look at SPWeb.Properties Property.
string strKey = "YourKey";
string strValue = "YourValue";
if (web.Properties.ContainsKey(strKey))
// if property exists then update it
web.Properties[strKey] = strValue;
else
// if property doesn't exist then add it
web.Properties.Add(strKey, strValue);
web.Properties.Update();

Resources