Tuesday, February 2, 2021

Validating azure directory token programmatically and getting details of user in C#

While creating an API to consume in our application or want to interact between applications. One of the key issue we need to address is to pass identity of authenticated user from our applications to our new applications or calling APIs. In my case it was a Azure function APIs which I need to authenticate before returning few details. Here I am referring how can we validate a passed a token in our API calls or app code. Here I am using a token issues by Azure AD so validating token using Microsoft namespaces. Below is the custom method I have written which we can call for validating token and get property of user for control. Here  I am returning email address of user:

public static string ValidateTokenAndGetEmail(string jwtToken, string appIssuer, string appAudience, string appSigningKey)
{
string email = "Invalid token.";
IConfigurationManager<OpenIdConnectConfiguration> configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(appSigningKey, new OpenIdConnectConfigurationRetriever());
OpenIdConnectConfiguration openIdConfig = AsyncHelper.RunSync(async () => await configurationManager.GetConfigurationAsync(CancellationToken.None));
TokenValidationParameters validationParameters =
new TokenValidationParameters
{
ValidateLifetime = true, 
ValidIssuer = appIssuer,
ValidAudiences = new[] { appAudience },
IssuerSigningKeys = openIdConfig.SigningKeys
};
SecurityToken validatedToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var user = handler.ValidateToken(jwtToken, validationParameters, out validatedToken);
// The ValidateToken method above will return a ClaimsPrincipal. Get the user ID from the NameIdentifier claim
// (The sub claim from the JWT will be translated to the NameIdentifier claim)
email = user.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
if (string.IsNullOrEmpty(email)) { {
                               email = "Invalid token.";
}
return email;
}


Let me talk bit about this parameters in function:

"jwt": "provide your token here, you can pass it through request header"

"AppTokenIssuer": "https://login.microsoftonline.com/<tid>/v2.0" --- tid needs to be cheked from azure admin. 

"AppTokenAudience": "<aud>"--- aud needs to be cheked from azure admin. 

"AppSigningKey": "https://login.microsoftonline.com/<tid>/.well-known/openid-configuration" --- tid needs to be cheked from azure admin. 

Namespaces we would need for these classes:

Microsoft.IdentityModel.Protocols;

Microsoft.IdentityModel.Protocols.OpenIdConnect

Microsoft.IdentityModel.Tokens

System.IdentityModel.Tokens.Jwt

System.Security.Claims

System.Collections.Generic

You need to add this additional class for execute task asynchronously:

internal static class AsyncHelper
{
private static readonly TaskFactory TaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);

public static void RunSync(Func<Task> func)
{
TaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
}
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return TaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
}
}

Tuesday, July 30, 2019

4 Essential Modern Basic JavaScript Features We Must Know


While going through some of the java script ES6 standards, I came across below 4 very useful features which can be very handy in daily use. I am keeping it as a note from a learning site.

·         Template literals  –

Before ES6, we had to deal with these ugly string concatenations:

var name = Krishna';
var message = 'Hi ' + name + ',';

Now, with template literals (previously called template strings), we can define a string with placeholders and get rid of all those concatenations:

var name = ‘Krishna';
var message = `Hi ${name},`;

Another benefit of using template literals is that they can expand multiple lines. They are particularly useful when composing email messages:

var message = `
Hi ${name},

Thank you for joining my mailing list.

Happy coding,
Krishna
`;


·         Let and Const   –

we used the var keyword to define variables. The scope of a variable defined using the var keyword is the entire enclosing function. Here’s an example:

const x = 1;
x = 2; // throws "Assignment to constant variable."

let x = 1;
console.log(window.x); // undefined
               
So, here is what you should take away:
·         Ditch the var keyword. Use only let and const.
·         Prefer const to let. Use let only if you need to re-assign the identifier; otherwise, use const to prevent accidentally re-assigning a constant.

·         Arrow Functions   –

Inspired by lambda expressions in C#, arrow functions give you a clean and concise syntax for writing function expressions. Here’s a function expression in ES5:

const square = function(number) {
   return number * number;
}

With arrow function:

const square = (number) => number * number;


·         Destructuring

Destructuring is an expression that allows us to extract properties from an object, or items from an array. Let’s say we have an address object like this:

const address = {
   street: '123 Flinders st',
   city: 'Melbourne',
   state: 'Victoria'
};

Now, somewhere else we need to access these properties and store their values in a bunch of variables:

const street = address.street;
const city = address.city;
const state = address.state;

      If we are using ES6:
     
      const { street, city, state } = address;
    
     Object destructuring is particularly useful when you’re dealing with nested objects:

const person = {
   name: 'Mosh',
   address: {
      billing: {
         street: '123 Flinders st',
         city: 'Melbourne',
         state: 'Victoria'
      }
   }
};

      Without destructuring, we would have to write this ugly and repetitive code:

const street = person.address.billing.street;
const city = person.address.billing.city;
const state = person.address.billing.state;
// So annoying!
   
      Now, we can achieve the same result using a single line of code:

const { street, city, state } = person.address.billing;


We  can try all these into our browser console. 

Wednesday, March 6, 2019

How to get weekending date(last friday) for each month in type script.

Call the method as below whenever you need it for current month based on current date.

console.log(this.getMonthLastWeekendDate());


//methods for it..

getMonthLastWeekendDate(): Date {
    const date = new Date();
    const y = date.getFullYear();
    const m = date.getMonth();
    const lastDay = new Date(y, m + 1, 0);
    const weekendingDate = this.getLastWeekDay(lastDay);
    return weekendingDate;
  }

  getNextDayOfWeek(date: Date, dayOfWeek: number): Date {
      const resultDate = new Date(date.getTime());
      resultDate.setDate(date.getDate() + (7 + dayOfWeek - date.getDay()) % 7);
      return resultDate;
  }

  getLastWeekDay(lastDay: Date): Date {
    let weekendingDateTemp;
      const dayOfWeek = lastDay.getDay();
      switch (dayOfWeek) {
        case 5:
          weekendingDateTemp = lastDay;
          break;
        case 6:
          weekendingDateTemp = this.getDateBeforeDays(lastDay, 1);
          break;
        case 0:
        weekendingDateTemp = this.getDateBeforeDays(lastDay, 2);
          break;
        default:
          weekendingDateTemp = this.getNextDayOfWeek(lastDay, 5);
        }
    return weekendingDateTemp;
  }

  getDateBeforeDays(inputDate: Date, numberOfDays: number): Date {
    const finaltempDate = new Date(inputDate.setDate(inputDate.getDate() - numberOfDays ));
    return finaltempDate;
  }

Wednesday, December 27, 2017

Run a local server using node.js for quick development.

It's a small tip for all the beginners out there. So many times especially when we are developing single page applications or working with git hub. We need to run a local server. Here I am telling you a very easy way to run a localhost at any of your folder.

1.  Install node into your machine. to install Node.js by downloading the installer for your OS from the official site
2. Once installed just got to your favorite location, create a new folder and create an index.html file.
3. I have C:\Users\krishna.mishra\dev\demo
4. Now open your powershell and navigate to this location.
5. Run this command http-server

6. Now you can browse your index.html file running this into browser.


Now you can run all your requests from this local server e.g. reading and writing a local JSON data resource etc. Hope it helps.

For more customization of node server and understanding of node, refer this awesome blog series Node.js Tutorial Series.

Saturday, December 17, 2016

How to get more items than threshold limit from SharePoint 2013/Online using REST API

While working with SharePoint, we always get stuck with the condition of not able to fetch more than threshold items(which is 5000 items per query). I have found a very easier way to get all item from a list into memory and the use it for binding, comparing or any other purpose, we want to use it for. Here my approach would be keep querying list till the time I am getting count equal to current threshold value.

 var fields = []; //All fields internal names
var expand = []; //Fields name to expand
var listName = string; // List title goes here
var listTemplate = []; // All records goes here, needs to be global
var ItemIDs = []; //An aarey to store Ids, needs to be global
function loadListData() {
   var ID = 0;
if(ItemIDs.length > 0)
    ID = ItemIDs[ItemIDs.length - 1];
$http({
method: "GET",
url: siteUrl + "/_api/web/lists/getByTitle('" + listName + "')/items()/"
+ "?$select=ID, " + fields
+ "&$expand=" + expand
+ "&$filter=ID gt "+ ID
+ "&$orderby=ID asc"
+ "&$top=5000", // SP limit is 100 by default
headers: { "Accept": "application/json;odata=verbose" }
}).success(function(data, status, headers, config) {
listTemplate = listTemplate.concat(data.d.results);
ItemIDs = ItemIDs.concat(data.d.results.map(function(v){ return (v.ID); }));
if(data.d.results.length == 5000) {
loadListData();
}
else {
   alert("Total records got from list are: " + ItemIDs.length);
//Next Function you want to execute after getting all records from list.
}
}).error(function (data, status, headers, config) {
 alert("Error while fetching data from list: "+ listName):
});
};

Just include this function with keeping these variables in global scope. Please let me know for any assistance or issues you face around it.

Friday, December 16, 2016

Get details of each user in SharePoint Site using ECMA Script

As you all are aware how tedious its to add find out details of each user into a SharePoint site.
There are only two ways for it first one is going to check permission option in site collection and then checking for each user one by one. Another option would be to get into each group ad then search for them.
To get rid of such time consuming process for users having no access to server, I have created a small piece of code script for getting details for all users using Client Side coding:

<html>
<head>
<script src="//code.jquery.com/jquery-1.12.3.js" type="text/javascript"></script>
<script src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css" /> 
<script type="text/javascript">
$(document).ready(function() {
    
} );
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', GetAllUsersInCurrentSite);
var groupUserMapping = [];
var AllUsersInSite = [];

    function GetAllUsersInCurrentSite() {
alert("Hi..");
var clientContext  = SP.ClientContext.get_current();
collGroup = clientContext.get_web().get_siteGroups();
clientContext.load(collGroup);
clientContext.load(collGroup, 'Include(Users)');
clientContext.executeQueryAsync(onQuerySucceeded,function() {});
}

function onQuerySucceeded(sender, args) {
var userInfo = '', groupInfo = '';
var groupEnumerator = collGroup.getEnumerator();
while (groupEnumerator.moveNext()) {
var oGroup = groupEnumerator.get_current();
var collUser = oGroup.get_users();
var userEnumerator = collUser.getEnumerator();
while (userEnumerator.moveNext()) {
  var oUser = userEnumerator.get_current();
  AllUsersInSite.push(oUser.get_id());
  groupUserMapping.push({GroupTitle: oGroup.get_title(), UserLoginName: oUser.get_loginName(), UserId: oUser.get_id(), UserTitle: oUser.get_title()});
}
}
var AllUniqueUserIds = AllUsersInSite.unique();
var Contacts = [];
AllUniqueUserIds.forEach(function(x){
var y =[];
var UserTitle = LoginName = '';
y["ID"] = x;
var groupVal = groupcount = '';
var groupMatch = groupUserMapping.filter(function (el) {
 return el.UserId == x;
});
if(groupMatch && groupMatch.length > 0) {
groupMatch.forEach(function(val){
groupVal += val.GroupTitle +", ";
UserTitle = val.UserTitle;
LoginName = val.UserLoginName;
groupcount = groupMatch.length;
});
}
y['UserName'] = UserTitle;
y['LoginName'] = LoginName;
y['GroupDetails'] = groupVal;
y['GroupCount'] = groupcount; 
Contacts.push(y);
});

$('#example').DataTable( {
        data: Contacts,
        columns: [
            { data: "UserName", title: "User Name"  },
            { data: "LoginName", title: "Login Name" },
            { data: "GroupDetails", title: "Group Names" },
{ data: "GroupCount", title: "Group Count" }
        ]
} );

}

Array.prototype.contains = function(v) {
    for(var i = 0; i < this.length; i++) {
        if(this[i] === v) return true;
    }
    return false;
};

Array.prototype.unique = function() {
    var arr = [];
    for(var i = 0; i < this.length; i++) {
        if(!arr.contains(this[i])) {
            arr.push(this[i]);
        }
    }
    return arr; 
}
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun /*, thisp*/) {
    var len = this.length >>> 0;
    if (typeof fun != "function")
    throw new TypeError();

    var res = [];
    var thisp = arguments[1];
    for (var i = 0; i < len; i++) {
      if (i in this) {
        var val = this[i]; // in case fun mutates this
        if (fun.call(thisp, val, i, this))
        res.push(val);
      }
    }
    return res;
  };
}
</script>
</head>
<body>
<table id="example" class="display" width="100%"></table>
</body>
</html>

Just need to make sure that you have access to internet as I am referring JQuery and Data table CDN. As soon you add this HTML file into a SharePoint Page CEWP. You would be able to see the details of each user, group names- user is part of, group count as below screenshot.



I have filtered it my name just to show my own membership with few generic groups. :)

Also just add reference to table export library and code to export this table into excel:

$("table[id='example']").tableExport({
headings: true,                    // (Boolean), display table headings (th/td elements) in the <thead>
footers: true,                     // (Boolean), display table footers (th/td elements) in the <tfoot>
formats: ["xlsx"],    // (String[]), filetypes for the export
fileName: "id",                    // (id, String), filename for the downloaded file
bootstrap: true,                   // (Boolean), style buttons using bootstrap
position: "bottom" ,                // (top, bottom), position of the caption element relative to table
ignoreRows: null,                  // (Number, Number[]), row indices to exclude from the exported file
ignoreCols: null ,                  // (Number, Number[]), column indices to exclude from the exported file
ignoreCSS: ".tableexport-ignore"   // (selector, selector[]), selector(s) to exclude from the exported file
});

We can also extend above functions to get details regarding users. Hope it helps someone.!



Tuesday, December 22, 2015

Easiest way to add Auto complete lookup to SharePoint 2013 or Online Form Fields using SPServices.

Today we will see how can we add an auto complete function to a SharePoint field in SharePoint 2013 or Online using SPServices. It will provide an easier way to provide user lookup functionality as a help instead of mandatory way and also add below code to on NewForm.aspx of your destination List by adding a Script Editor Webpart:

<script language="javascript" src="//code.jquery.com/jquery-1.6.2.min.js"
type="text/javascript"></script>
<script language="javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery.SPServices/2014.02/jquery.SPServices-2014.02.min.js"
type="text/javascript"></script>
<script type="text/javascript">
    $(document).ready(function () {
        $().SPServices.SPAutocomplete({
            sourceList: "SourceList", // Source List Name
            sourceColumn: "Title", // Source List Column from where you want to fetch it.
            columnName: "DestinationListColumn", // Destination List Column where you wan to add it.
            ignoreCase: true,
            numChars: 2,
            slideDownSpeed: 'fast'
        });
    });</script>