Monday, June 24, 2013

Hide Columns in a SharePoint list based on SharePoint group

It seems to be a fairly common request to hide particular columns on a SharePoint form based on the SharePoint group that a user is a member of. One solution to this problem would be to create custom forms for Add, Edit, and Display in SharePoint using SharePoint designer. Then figure out a way to hide and show the columns. This requires SharePoint Designer access and may not always be an option. It also requires the user to read through ASP.NET / XSL markup and figure out how to do it. This is a very tedious task and hardly easy to maintain. The good news is that this is a truly secure solution since the data is not sent to the client (browser). If you have these strict security requirements then you may want to go this route. FYI, I have read that InfoPath is also an option, but I don't like going that route either.

I am working on an internal instance of SharePoint 2010 and simply hiding the data on the forms using CSS is sufficient because the user would have to look in the source of the page to see the data.

WARNING:
Note: This is NOT a true security solution! All data (even for hidden columns) is sent to the browser, but is just hidden from user's view in the browser.

In my case, it would not be the end of the world if users viewed source to see all the data. We are all part of the same company after all. If this is your scenario, then you may want to consider the solution outlined below.

My solution uses a JavaScript library called SPUtility.js. It makes hide and showing a field simple. It also makes changing a field to readonly simple as well. I can't take credit for the library, but I am very happy I found it. The only problem left to solve was how to get the current user and the groups that the user is in. This is something I had to come up with. It requires CSOM (Client Side Object Model) which requires SharePoint 2010 or later. I read that you can use SPServices if you are using MOSS 2007, but I have not tried to do it.

To implement the functionality to get user and group information, I wrote the following methods.

You can download the source here.

function getCurrentUserObject(callbackFunc)

function isCurrentUserInSharePointGroup(sharePointGroupID, callbackFunc)

function isUserInSharePointGroup(userLogin, sharePointGroupID, callbackFunc)

CSOM uses asynchronous calls for everything which makes it difficult to code if you are not accustomed to it. The good news is all you have to do is provide the callback function to make use of these functions. While that may sound difficult, just follow the example I have provided. In the example code the first thing it does is make sure the CSOM library (sp.js) is loaded and then executes our code. It takes the approach of getting the current user then seeing if the user is in the owner group and setting column visibility appropriately. If the user is not in the owner group it then looks in the members group and sets the column visibility appropriately. If they are not in either of those groups it sets the column visibility appropriately. You could continue on with different checks if desired.

Here is a snippet of what the solution code looks like:

function doOwnerChanges(userLogin, isInGroup)
{
  if (isInGroup)
  {
 
   SPUtility.GetSPField('Title').Show();
   SPUtility.GetSPField('Cost').Show();
   SPUtility.GetSPField('Customer Comment').Show();
   SPUtility.GetSPField('Assigned To').Show();
   SPUtility.GetSPField('Internal Comments').Show();
  }
  else // not in owner group let's see if they are in members group
  {
 
   isUserInSharePointGroup(userLogin, 7, Function.createDelegate(this, this.doMemberChanges));
 
  }
}


As you can see it is easy to maintain because all the complexity is abstracted away. If another column is added you would just add a line to the above code.



Added solution to your page

  1. Download the following:
    • SPUserGroupUtility.js My code that gets the current user and checks the groups the user is in.
    • ShowHideColumnExample.js (only needed if you want an example of how to use this solution). You can replace or not use this in your specific implementation. This is the file you will need to specify your columns. The name is not important except that you reference it later.
    • SPUtility.js This provides the functionality for hide/showing fields and making them readonly, etc.
    • Prototype.js Required by SPUtility.js.
    • sp.js - actually you don't need to download it. Ultimately, this is the CSOM library. It is provided by SharePoint 2010. Just use it in your code as needed.
  2. Upload the .js file to somewhere on SharePoint where all users can access the files. I recommend installing your .js file in your Site Assets directory on your site. You can find it by going to Site Action | View All Site Content | Site Assets.
  3. Navigate to form (EditForm.aspx or NewForm.aspx)
    In SharePoint 2010, you can choose Form Web Parts -> Default whatever Form
  4. Add a Content Editor Web Part to the page
  5. Edit the web part
    In SharePoint 2010, click the arrow -> Edit Web Part.
  6. Edit the content editor's HTML to add some JavaScript
    In SharePoint 2010, under Editing Tools -> Format Text click the HTML button -> Edit HTML Source
  7. Follow the instructions on installing the SPUtility.js
  8. <script src="/sites/someSite/SiteAssets/prototype.js" type="text/javascript"></script>
    <script src="/sites/someSite/SiteAssets/SPUtility.js" type="text/javascript"></script>
    <script src="/sites/someSite/SiteAssets/ShowHideColumnExample.js" type="text/javascript"></script>
    <script src="/sites/Brent/SiteAssets/SPUserGroupUtility.js" type="text/javascript"></script>
  9. Save the page / stop editing.

Troubleshooting

  • NOTE: To just try SPUtility.js you can try the install instructions.
  • If nothing happens on the page, make sure you don't have any errors. You may need to do an F12 in IE to see the error console. Also, you can look at the F121 | Network tab to see if the JavaScript files are able to be found.
  • You can always start the JavaScript debugger and see where it is breaking.

Tuesday, June 18, 2013

Authenticating a user against a specific domain (C#)

In the example below I am authenticating an imaginary user called usernameHere that has a password of passwordHere against the mydomainHere.com domain. In this example, the user would normally login using something like this: mydomainHere\usernameHere and then enter the password. The .com was added to the domain because that is typically how domains are set up. However, if you have a different long name for the domain, you should use that.

using using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;

...
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "mydomainHere.com"))
{
     // validate the credentials
     bool isValid = pc.ValidateCredentials("usernameHere", "passwordHere", ContextOptions.Negotiate);
     Console.WriteLine("Valid: " + isValid);
    
}


You will need to add a reference to System.DirectoryServices.dll and System.DirectoryServices.AccountManagement.dll in order for this to work. If you don't have version 3.5 or newer of .NET, you will not have these methods available to you. This link has many other methods that you can try.

As a side note, here is a article that shows lots of code snippets for doing common tasks in Active Directory using C#.

Wednesday, June 5, 2013

Crontab

I can never seem to remember how to use crontab. I found a good resource for it that has lots of examples and good explanation of things. Check it out. This is also a good one.

The highlights that I want to remember are:

crontab -l
This is used to see what is scheduled to be executed and when.

crontab -e
Opens the vi text editor to allow changes to the crontab. In most implementations that I have seen the changes are automatically picked up by crontab
vi remember:
  • ESCAPE then ZZ to save changes
  • ESCAPE then :q to quit and not save changes
  • ESCAPE then i to go into edit mode
Each line in the crontab has the format:
min hr dom month dow cmd

  • minute This controls what minute of the hour the command will run on, and is between '0' and '59'
  • hour This controls what hour the command will run on, and is specified in the 24 hour clock, values must be between 0 and 23 (0 is midnight) 
  • dom This is the Day of Month, that you want the command run on, e.g. to run a command on the 19th of each month, the dom would be 19.
  • month This is the month a specified command will run on, it may be specified numerically (0-12), or as the name of the month (e.g. May)
  • dow This is the Day of Week that you want a command to be run on, it can also be numeric (0-7) or as the name of the day (e.g. sun). 
  • user This is the user who runs the command. 
  • cmd This is the command that you want run. This field may contain multiple words or spaces
Some examples:
30 7 * * * /opt/tomcat/myApp/run.sh "This command is run daily at 7:30 am"
0 * * * * echo "This command is run hourly"

Special Keywords that can be used instead of the 5 part specifiers
@yearly 0 0 1 1 *
@daily 0 0 * * *
@hourly 0 * * * *
@reboot Run at startup.
For example:
@yearly /home/ramesh/red-hat/bin/annual-maintenance