Tuesday, November 20, 2012

SharePoint Discussion Board - Hide (View/Edit) Link

How do you conditionally hide (View Item) Link on the threaded view?
It is not the best way, in which the discussion board has the link displayed on the UI. Technically, there is a setting that you can set where a user who creates the post is only allowed to edit. However, that check only occurs when you click on Edit Item and SP will either display the edit page or will give access denied.

This is the JQuery I wrote to hide the link for each post comparing signed in user to the user who posted. If the 2 names are different, I hide the link and if they are same I replace the display value with "View/Edit".

$("a[href*='_layouts/userdisp.aspx']").each(function (index) {
            if ($(this).text().length > 0) {
                if ($(this).text().toLowerCase() != jQuery.trim(thisUserAccount.toLowerCase())) {
                    // Work $(this).parent().parent().parent().parent().parent()[0].firstChild.nextSibling.innerText = '';
                    $(this).parent().parent().parent().parent().parent()[0].firstChild.nextSibling.firstChild.firstChild.innerHTML = ''
                }
                else {
                    $(this).parent().parent().parent().parent().parent()[0].firstChild.nextSibling.firstChild.firstChild.innerHTML = '<NOBR>Edit/Delete</NOBR>';
                }
            }
        });

Monday, June 25, 2012

User Profile Service & ADFS in Multi-Tenant

For the past several weeks, I have been working in getting ADFS work in dedicated environment. The process is fairly simple once you have a server with ADFS running.
Here is a list of things you need in SP:
  1. Token Signing Certificate of ADFS Server.
  2. IIS Web Server Certificate of the server hosting ADFS.
  3. Atleast Self Signed SSL Cert of the IIS Server that is hosting SP.
  4. You need to define your claims in ADFS and then map them as well.
  5. Finally, you have to write a power shell script something like this in order to set up the new token identifier.


write-host "Adding ADSF Cert"
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\ADFS\adfs.cer ")
New-SPTrustedRootAuthority -Name "Token Signing Cert" -Certificate $cert

$map = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" -IncomingClaimTypeDisplayName "EmailAddress" -SameAsIncoming
$map2 = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" -IncomingClaimTypeDisplayName "Role" -SameAsIncoming
$map3 = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" -IncomingClaimTypeDisplayName "GivenName" -SameAsIncoming
$map4 = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" -IncomingClaimTypeDisplayName "SurName" -SameAsIncoming
$map5 = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname" -IncomingClaimTypeDisplayName "windowsaccountname" -SameAsIncoming
$map6 = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid" -IncomingClaimTypeDisplayName "GroupsId" -SameAsIncoming

$realm = "urn:seo:sharepointMT"

write-host "Setting up STS in SharePoint"
$ap = New-SPTrustedIdentityTokenIssuer -Name "ADFS Provider" -Description "SharePoint secured by SAML" -realm $realm -ImportTrustCertificate $cert -ClaimsMappings $map,$map2,$map3,$map4,$map5,$map6 -SignInUrl "https://ADFSServer/adfs/ls" -IdentifierClaim "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"

#This is ADFS Web Serv cert
$certPath = "C:\ADFS\MachineCert.cer"
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(“$certPath”)
New-SPTrustedRootAuthority “ADFS web server” -Certificate $cert

#This is the cert associated with the server running IIS/SP
$mycert = New-Object System.Security.Cryptography.x509Certificates.x509Certificate2("C:\ADFS\VM55.cer");
New-SPTrustedRootAuthority –Name "IISSSL" –Certificate $mycert;


User Profile Service using ADFS



In order to get this to work, there are a few things that have to be done before synchronizing users.

Here is a list:
  • Port 389 has to be opened on network that has ADFS Server running.
  • An AD User who has delegate permission/replicate should be created and provided to SP
  • Then, you can  go to User Profile Service and add new connection and choose ADFS as login method. When you choose ADFS, your STS provider will be listed in a drop down. Choose that. Then, put the user and password of the AD User that was created above to save.
  • Finally, start incremental/full import.
 ADFS & Multi-Tenancy

I did not find a lot of information on this where ADFS will work in multi-tenancy. In Office 365, it works, but that is on cloud. I started on this after finishing the above 2 big technical blocks. I was able to SUCCESFULLY set up ADFS in a multi-tenant environment.

You may have a scenario where there are 2 Tenants that are connected to different ADFS servers and you only want to display the STS they are mapped to. This can be accomplished by creating a custom login page which has a drop down with the name of STS provider that tenant is mapped. This drop down can be populated in multiple ways.

UPS using ADFS in multi-Tenant

This was the grand daddy of all the above or in other words the cherry on top of this massive technical sundae. I got this to work as well. This was not bad, but the only catch here is that you have to set OU when provisioning tenants. There is a document on Harbar.net that provides details on how you set up OU, but other than that it is fairly similar to dedicated environment. The other noted difference is that you use the UPS of CA, to set up connection and so forth. However, you need to goto Tenant's CA, to see all the users.

If you are having difficulties in getting this to work, here is a list of things that you may want to check:
  • You should be able successfully login via ADFS.
  • Port 389 is open
  • User with appropriate permission has been used. (Note: A Farm Admin or System admin will not help)
  • Check Fore Front Identity Management for the successes and failures.
If the above still does not help, it is time to open SQL Server that is associated with SP. This not the thing you should be touching, but if above things are all correct, you would have to open the Profile database. In that database, look at Tenant table and look at SynchronizationOU column. This column should have the appropriate OU, you have defined for the Tenant. Then, finally look at the UserProfile_Full and ensure that the users exists and if they do, check the partition id so to ensure they are mapped to the right tenant.

Saturday, March 10, 2012

Supercharged Content Query WebPart

For the last 2 weeks, I have been working on a very challenging assignment that another senior SharePoint architect stated that cannot be done. Here is a scenario; we want to dynamically pull the data from a list based upon a hierarchy structure that is tied to the user who has logged in to the system. The most obvious choice would be to use Content Query Web Part. The challenge here is that we are limited by 3 filters and what if we want to bring the data from Parent and its 8 children. This is not possible unless we start writing massive CAML.

Here is the solution I implemented for solving this problem. You create a webpart that inherits directly from CQWP and then in that class you can set your filters depending upon your requirements. Remember we cannot have more than 3 filters with CQWP even when we overwrite via VS. The key part of the solution is to map our hierarchy structure with a Term Store. The reason why this is a very cool idea is because in SP 2010 term store are 100% integrated with CQWP. When you define a column in the list of type managed metadata then you can use that as one of the filters in CQWP. When you use this column in CQWP, it gives you an option to include children as this is now supported in SP2010.

The other key aspect of this solution was to via code to set the filter based on the term that is associated with the current user. In the initialize of the inherited subclass, we will add code something like this, which will dynamically set the filter every time the webpart is executed.

this.FilterField1 = “Taxonomy Field Name”;

this.FilterOperator1 = ContentByQueryWebPart.FilterFieldQueryOperator.ContainsAny;

this.Filter1ChainingOperator = ContentByQueryWebPart.FilterChainingOperator.Or;

this.FilterType1 = "TaxonomyFieldTypeMulti";

this.FilterIncludeChildren1 = ShouldHaveDescedant();

this.FilterValue1 = ResolveFilterValue();

I don't want to get into the details about the power of CQWP on its own, but now when we combine CQWP with taxonomy we are going to produce a supercharged version of CQWP.

Sunday, February 19, 2012

How to marry AD Claims User and Forms Based Users?

    I have been working at a client that uses FB authentication model to authenticate all users and to create new users. This works great as everything is with the SQL Server and you could associate users to different locations/departments, which are defined in SQL Server.

    However, there are scenarios where internal users need to log to SP site and they don’t necessarily have to use their FB authentication. There are other scenarios where the user may not exist in FB system, but in order to use the system they have to be created/registered in FB system. It would be really cool, if we could have the system in such a way that when an AD user logs to the SP Site, the system looks if the user exists in the FB database, if not, then checks a flag to see if I can auto add this new user all at once.

    How do you do such a thing where you can auto add an AD user with their groups as they are mapped to different locations the user exists and their other data(Title/Phone…etc)? This involves a couple of different components within SP/.NET world. First, you would need to examine the claims the user is bringing when coming via AD world. This is the most important step in the process as if you cannot find the UPN, then everything will break. You would need to have the email address of the AD user also to examine if the system already has a user in the database. We have an assumption that FB/AD user have the same email address as technically they are 2 different users, but we trying to impersonate AD user with FB user. The next thing you would need is to use the identity framework to examine what are the groups users belongs to so that you can map them to locations/departments in the system. Finally, you would need to active User Profile Service in order to extract other pieces of information like Title, Phone number etc. Once you have collected all this data, you can easily go ahead and create the FB user with this information.

    Thereafter, every time an AD user logs into the system, we query the db to find associated FB user and then make every single call as if the FB user is making. This is in brief how you would marry AD with FB 