Showing posts with label Office 365. Show all posts
Showing posts with label Office 365. Show all posts

Tuesday, February 7, 2017

Tips to resolve "Access is denied" error when running Office 365 Compliance Center reports from Remote PowerShell command line

You can use the Office 365 activity report in the Office 365 Compliance Center to view user and admin activity in your Office 365 organization. The report contains entries from the Office 365 user and admin activity log for activity in SharePoint Online, OneDrive for Business, and Azure Active Directory, which is the directory service for Office 365. In our case, we are interested in the Audited events in the Office 365 activity report.

Since the report from UI only display 100 record, it would be much easier to manage yourOffice 365 Compliance Center settings from the Remote PowerShell command line. You use Windows PowerShell on your local computer to create a remote Shell session to the Compliance Center. It’s a simple three-step process where you enter your Office 365 credentials, provide the required connection settings, and then import the Compliance Center cmdlets into your local Windows PowerShell session so that you can use them.

Access is denied is the most common error when you use the Office 365 Compliance Center settings from the Remote PowerShell command line. There are at least two different Access is denied error as below.

New-PSSession :  [ps.compliance.protection.outlook.com] Connecting to remote server ps.compliance.protection.outlook.com failed with the following error : Access is denied.

New-PSSession :  [ outlook.office365.com] Connecting to remote server outlook.office365.com failed with the following message :
[ClientAccessServer=BY1PR13CA0016,BackEndServer=by1pr02mb1193.na,prd02.prod.outlook.com,RequestId=bf4b2467-03cf-465a-bf9d-6c5574a49f92,TimeStamp=6/1/2015 10:51:51 PM] Access Denied

There are two common issues that are permission issue and MFA configuration we will explain below to eliminate the access denied error. 

First, you should grant the proper permissions to the account that will run the Office 365 Compliance Center reports. You should need to make sure all the following permissions assigned to this account.
You could following the links to assign the first two permissions. Since the compliance center is leverage the exchange search on the backed, this account would need to assign the exchange license and then add exchange compliance administrator permission. You could browse to the exchange admin center and within permissions add the same account under Compliance management as in the below screenshot. This seems to be logical since the reports are leverage the exchange architecture. 




Second, you might need to disable the MFA for the account. At this time, the Remote PowerShell command line does not support MFA and this seems to be obvious. You could disable the MFA by browse the active users and select MFA settings as below screenshot.




You will find the error from Powershell log if the account is MFA enabled. You could use the Powershell to verify whether this account is MFA enabled or not. 

Get-MsolUser -UserPrincipalName <upn of the user>| fl

Here are the example attributes that will indicate whether MFA is enabled for a user or not:
StrongAuthenticationRequirements       : {Microsoft.Online.Administration.StrongAuthenticationRequirement}
StrongAuthenticationUserDetails        :
StrongPasswordRequired                 : True

Now you should have the account that could be used to generate the Office 365 activity report. Here is the sample script you could adjust for your own purpose.

$UserCredential = Get-Credential

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection

Import-PSSession $Session

$logs = Search-UnifiedAuditLog -StartDate "3/1/2015" -EndDate "3/7/2015" -RecordType SharePointFileOperation

#I would like to exclude the O365 crawl account activities from the report
$logs | %{$_.AuditData} | ConvertFrom-Json | ? {$_.userid -ne '0#.w|ylo001\_spocrwl_162_11435'} |
#select the properties you really need below, if you need all the properties - skip the Select statement, and directly pipe to CSV.
select userid,userkey,creationtime,operation,objectid,itemtype,siteurl,sourcefilename,sourcerelativeurl  |
Export-Csv -Path E:\logs-3-1.csv

There are some options you could use for Search-UnifiedAuditLog command.


SYNTAX
Search-UnifiedAuditLog
-StartDate <ExDateTime> #Search start time, e.g. "2/1/2015" or "2/1/2015 3:15pm"
-EndDate <ExDateTime> #Search end time, e.g. "2/1/2015" or "2/1/2015 3:15pm"
[-RecordType <AuditRecordType> {ExchangeAdmin  | ExchangeItem | ExchangeItemGroup | SharePoint | SyntheticProbe | SharePointFileOperation | OneDrive}]
[-ObjectIds <string[]>] #Array of objects, could be partial name, e.g. @(“document”, “.docx”) or “.pptx”
[-UserIds <string[]>] #Array of user Ids, e.g. @(“joe@contoso.com”, “bob@contoso.com”) or “kata@contoso.com
[-Operations <string[]>] #Array of operation or event names, e.g. @(“FileDownload”, “FileView”) or “SharingSet”
[-FreeText <string>] #Full text search against any text within events
[-ResultSize <int>] #Top N records to return

[-Identity <UnifiedAuditLogEventIdParameter>] #Id to represent a record, if you want to re-search this exact events

We found the current O365 Activity report only returns 2,000 most recent events in the last 7 days are returned from Remote Powershell. The auditing is designed to keep just 30 days at this time. The powershell does not return the following  user login actions as you could get from UI.
  • ForeignRealmIndexLogonInitialAuthUsingADFSFederatedToken
  • PasswordLogonInitialAuthUsingPassword
I heard from Microsoft Ignight conference that Microsoft will have a plan to provide Management API we could use in the future to leverage REST calls to interact the O365 reports and it will provide service to keep audit data forever. These changes will be extremely helpful to automate the reports and provide solution for compliance and auditing requirements.


Tuesday, September 22, 2015

SharePoint online lits item created by process using Azure AD token does not trigger out of box approval workflow

We have identified one issue when creating the SharePoint list item using Azure AD token. It does not trigger the out of box approval workflow!

You could reproduce this easily by creating an console application using Azure AD token. The console client example I’m using the code copied from Richard diZerega.

Here are the steps to reproduce. 
  • Create a custom list
  • Add approval workflow to the list
  • Add item manually and verify it will trigger approval workflow
  • Create an item to the same list using Azure AD  app token does no trigger approval workflow

The following error in the logs when debugging with Microsoft.
Declarative workflows cannot automatically start if the triggering action was performed by an App-Only request. Canceling workflow auto-start. List Id: adaa6f76-bcd4-4fb7-8047-79345de1a362, Item Id: 12, Workflow Association Id: 03c8887c-d816-4a31-9181-71de9ed10523

This seems to be happening as SharePoint is considering the workflow as running under System Account. You might recall we need to run powershell to enable declarative workflow.

One interesting finding is the item created by same REST by using end user name and password described in different blog will trigger approval workflow. If you are using Azure AD token to authenticate to O365, the item created will be created by Azure app instead of the real user as in the following screenshot.

Another interesting finding is item created using Azure AD token will trigger other workflows like Three State workflow and Disposition workflow. 

The third interesting finding is the workflow starts fine for a provider hosted app for approval workflow. You will see some workflows failed in the below screenshot.

After working with Microsoft O365 team on this strange behavior and it turns out this is as designed. This is to prevent ADA attack. The error from the log is listed below.

SPWorkflowAutoStartEventReceiver: ItemAdded event received for list adaa6f76-bcd4-4fb7-8047-79345de1a362, item id 12
Declarative workflows cannot automatically start if the triggering action was performed by an App-Only request. Canceling workflow auto-start. List Id: adaa6f76-bcd4-4fb7-8047-79345de1a362, Item Id: 12, Workflow Association Id: 03c8887c-d816-4a31-9181-71de9ed10523
Correlation ID = f192309d-d049-2000-0a07-38a8143f17b7


If you really need to trigger workflow by using Azure AD token to create items, the workaround is to create a designer 2013 workflow. I've created a designer 2013 workflow and it was successfully triggered as in the below screenshot. The designer workflow named "Approval2013WF" has only one send email action.


Please note the item added event will be triggered and you could add business logic in the remote event receiver to perform some actions. You might not be able to sue the same token to modify the SharePoint objects.

Monday, September 14, 2015

Authenticate to Office 365 and SharePoint Online option #3 - REST using Azure AD from C#

When working on SharePoint Online as a new developer, there is always some confusion how to connect and authenticate to the SharePoint site. I’ve summarized two ACL options based implementation in previous blogs. Both implementations are using users’ O365 use name and password to communicate with SharePoint online.


The limitation of ACS approach is you are using end user’s credential that is configured to have limited access to restricted systems. It would be difficult leveraging multiple services secured by Azure AD for some use case like background bulk process. This blog will demonstrate the C# code to leverage Azure AD making app-only calls into SharePoint Online. This provides a more secure way of performing background operations against Office 365 services. In this blog you would need to have a certificate deployed to Azure AD application for the authenticate, I’ll have a different approach in future blog to leverage Azure AD without using certificate.

In order to leverage Azure AD to connect to SharePoint Online, you could need to create a Azure AD application. You could follow the steps Richard diZerega’s blog on the details. I’m using the procedure I’m using in the session “Application registration in Azure AD” from Office 365 Management APIs starting guide.


Here is the code sample to use the Azure AD application that is based on RicharddiZerega’s blog. 

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace RESTAzureToken
{
    class Program
    {
        private static string CLIENT_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";   // Azure AD application client ID. It should be a ~35 character string
        private static string PRIVATE_KEY_PASSWORD = "MyCertPassword";  // I’ll have different example in the future to eliminate the password
        static void Main(string[] args)
        {
            doStuffInOffice365().Wait();
        }

        private async static Task doStuffInOffice365()
        {
            //set the authentication context
            string authority = "https://login.windows.net/mycompany.onmicrosoft.com/";
            AuthenticationContext authenticationContext = new AuthenticationContext(authority, false);

            //read the certificate private key from the executing location
            var certPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
            certPath = certPath.Substring(0, certPath.LastIndexOf('\\')) + "\\QCMAPICert.pfx"; // The Cert you uploaded to Azure AD application
            var certfile = System.IO.File.OpenRead(certPath);
            var certificateBytes = new byte[certfile.Length];
            certfile.Read(certificateBytes, 0, (int)certfile.Length);
            var cert = new X509Certificate2(
                certificateBytes,
                PRIVATE_KEY_PASSWORD,
                X509KeyStorageFlags.Exportable |
                X509KeyStorageFlags.MachineKeySet |
                X509KeyStorageFlags.PersistKeySet);
            ClientAssertionCertificate cac = new ClientAssertionCertificate(CLIENT_ID, cert);

            //get the access token to SharePoint using the ClientAssertionCertificate
            Console.WriteLine("Getting app-only access token to SharePoint Online");
            var authenticationResult = await authenticationContext.AcquireTokenAsync("https:// mycompany.sharepoint.com/", cac); // Do not use the site "https:// mycompany.sharepoint.com/sites/MyTestSite"
            var token = authenticationResult.AccessToken;
            Console.WriteLine("App-only access token retreived");

            //perform a post using the app-only access token to add SharePoint list item in Attendee list
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
            client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");

            const string siteURL = "https://mycompany.sharepoint.com/sites/MyTestSite";

            // Get list from title
            const string listAction = siteURL + "/_api/web/lists/getbytitle('TestList')";
            HttpResponseMessage listResult = await client.GetAsync(listAction).ConfigureAwait(false);
            listResult.EnsureSuccessStatusCode();
            string listJsonData = await listResult.Content.ReadAsStringAsync();
            Console.WriteLine(listJsonData);

            // Get all items from list
            const string itemAction = siteURL + "/_api/web/lists/getbytitle('TestList')/items";
            HttpResponseMessage response1 = await client.GetAsync(itemAction).ConfigureAwait(false);
            response1.EnsureSuccessStatusCode();
            string itemJsonData = await response1.Content.ReadAsStringAsync();
            Console.WriteLine(itemJsonData);

        }
    }
}

The result of the items isin json format and here is the screenshot of the data from json viewer.



If you are new to O365 development, you should be aware of the following configurations in order to avoid some common errors.

1. Do not use the user friendly Microsoft new O365 URL like “mycompany.sharepoint.com”. Use the https://login.windows.net/mycompany.onmicrosoft.com/ as authority string. Otherwise you will get the error below.

Tracing:TraceError: "9/2/2015 11:57:02 PM: 542878bc-c518-4339-be97-41fe5f6ed523 - <RunAsync>d__0: Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: AADSTS90002: No service namespace named mycompany.sharepoint.com' was found in the data store.
Trace ID: ca2c8bba-655a-4b01-89b3-23367373c274
Correlation ID: 542878bc-c518-4339-be97-41fe5f6ed523
Timestamp: 2015-09-02 23:57:01Z ---> System.Net.WebException: The remote server returned an error: (400) Bad Request.

2. Use the O365 tennant entry point URL instead of the site to acquire token.
var authenticationResult = await authenticationContext.AcquireTokenAsync("https://qualcomm.sharepoint.com/", cac);

If you pass the site URL 'https://mycompany.sharepoint.com/sites/SPDEV/', you will get the error below.

Exception:Caught: "AADSTS50001: Resource 'https://mycompany.sharepoint.com/sites/SPDEV/' is not registered for the account.
Trace ID: 702ef6fd-c156-4d6c-99b6-f5bb18eae6c8
Correlation ID: 0b25a990-c74c-4244-934a-90d138f66b40
Timestamp: 2015-09-02 16:41:16Z" (Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException)
A Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException was caught: "AADSTS50001: Resource 'https://qualcomm.sharepoint.com/sites/SPDEV/' is not registered for the account.
Trace ID: 702ef6fd-c156-4d6c-99b6-f5bb18eae6c8
Correlation ID: 0b25a990-c74c-4244-934a-90d138f66b40
Timestamp: 2015-09-02 16:41:16Z"
Time: 9/2/2015 9:41:16 AM
Thread:Worker Thread[10072]

3. When you are generating the X.509 certificate, make sure the key length is at least 2048. Shorter key lengths are not accepted as valid keys.

4. Manifest cannot not be re-uploaded unless you set variable $base64Value to null. If you change the certs, I'm not sure how to replace it to the exiating Azure AD application. There might be a powershell to do that but I've not find it.

5. The following packages you would need to ad to the references.
  • Active Directory Application Library
  • Json.NET package
  • System.Net.Http package

6. Be aware of the O365 MFA configuration and you might need to run this app inside your company firewall as I explained in previous blog.

Friday, September 11, 2015

Authenticate to Office 365 and SharePoint Online option #2 - REST using SharePointOnlineCredentials object from C#

When working on SharePoint Online as a new developer, there is always some confusion how to connect and authenticate to the SharePoint site. I’m summarizing all the different authenticate ways so my developers could choice one appropriate approach for their projects.


In this blog, I’ll illustrate the C# REST example using SharePointOnlineCredentials object. In this case, you need to pass the user name, password, and the REST end point. The following example illustrated the REST API to get list from title and get all items from one list.


using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using Newtonsoft.Json.Linq;

namespace RESTClient
{
    class Program
    {
        static void Main(string[] args)
        {
            const string siteURL = "https://mycompany.sharepoint.com/sites/SPDEV";
            const string actionREST = siteURL + "/_api/web/lists/getbytitle('TestList')";
            const string userName = "userID@mycompany.com";
            const string password = "mypassword";

            // Get the list jason result
            Task<string> result = getRestResult(siteURL, actionREST, userName, password);
            result.Wait();
            string jasonResult = result.Result;
            Console.WriteLine(jasonResult);

            // Get list Title from jason result
            var obj = JObject.Parse(jasonResult);
            var title = (string)obj.SelectToken("Title");
            Console.WriteLine(title);

            // Get all items jason result
            const string actionRESTItem = siteURL + "/_api/web/lists/getbytitle('TestList')/items";
            Task<string> resultItems = getRestResult(siteURL, actionRESTItem, userName, password);
            resultItems.Wait();
            string jasonItemResult = resultItems.Result;
            Console.WriteLine(jasonItemResult);

            // Get each item from jason result


        }

        private static async Task<string> getRestResult(string siteURL, string actionREST, string userName, string password)
        {

            //Creating SharePointOnlineCredentials 
            var securePW = new SecureString();
            foreach (var c in password) securePW.AppendChar(c);
            var credential = new SharePointOnlineCredentials(userName, securePW);

            //Creating Handler to allows the client to use SharePointOnlineCredentials
            using (var handler = new HttpClientHandler() { Credentials = credential })
            {
                //Getting authentication cookies 
                Uri uri = new Uri(siteURL);
                handler.CookieContainer.SetCookies(uri, credential.GetAuthenticationCookie(uri));

                //Invoking REST API 
                using (var client = new HttpClient(handler))
                {
                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                    HttpResponseMessage response = await client.GetAsync(actionREST).ConfigureAwait(false);
                    response.EnsureSuccessStatusCode();

                    string jsonData = await response.Content.ReadAsStringAsync();
                    return jsonData;
                }
            }
        }


    }
}

The nest step is to parse the jason return string to get each item details. We will provide examples in the future.

Thursday, September 10, 2015

How to resolve error “Microsoft.SharePoint.Client.IdcrlException: The sign-in name or password does not match one in the Microsoft account system” when using CSOM for O365/SharePoint online

One of the easiest way to communicate to O365 and SharePoint Online is through CSOM code as we described in previous blog. The code is extremely easy however some people run into the following common error.

Unhandled Exception: Microsoft.SharePoint.Client.IdcrlException: The sign-in name or password does not match one in the Microsoft account system.
   at Microsoft.SharePoint.Client.Idcrl.IdcrlAuth.GetServiceToken(String securityXml, String serviceTarget, String servicePolicy)
   at Microsoft.SharePoint.Client.Idcrl.IdcrlAuth.GetServiceToken(String username, String password, String serviceTarget, String servicePolicy)
   at Microsoft.SharePoint.Client.Idcrl.SharePointOnlineAuthenticationProvider.GetAuthenticationCookie(Uri url, String username, SecureString password, Boolean alwaysThrowOnFailure, EventHandler`1 exe
cutingWebRequest)
   at Microsoft.SharePoint.Client.SharePointOnlineCredentials.GetAuthenticationCookie(Uri url, Boolean refresh, Boolean alwaysThrowOnFailure)
   at Microsoft.SharePoint.Client.ClientRuntimeContext.SetupRequestCredential(ClientRuntimeContext context, HttpWebRequest request)
   at Microsoft.SharePoint.Client.SPWebRequestExecutor.GetRequestStream()
   at Microsoft.SharePoint.Client.ClientContext.GetFormDigestInfoPrivate()
   at Microsoft.SharePoint.Client.ClientContext.EnsureFormDigest()
   at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()
   at CSOM.Example.Program.Main(String[] args)


This error may be inconsistent and you might have this issue when you are not on the corporate network like people reported here. After debugging this issue, there are several common areas you could check to resolve this quickly.

1. Verify whether the user name and password directly from O365 UI. If this account has been disabled or changed, you could verify immediately.

2. Verify whether you have MFA enabled if using ADFS for this account. Normally we enabled MFA for security reason and apply rule to be trigger if the request is coming from non-trusted source like non company network. This might be the #1 reason why the same code is working when the machine is on the corporate network and exception when undock the machine. You could refer Microsoft instruction to disable the account is the code need to be run off the corporate network.

3. Verify you have latest SharePoint client dlls. SharePoint client libraries may change based on different releases. You might need to upgrade the client library and here is the latest version.

4. Loopback  enabled is common issue for WFC web service and you might need to disable it. Disabled the loopback check entirely by creating REG_DWORD DisableLoopbackCheck at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa and setting value to Decimal 1.

This is the list of the most common configurations that might cause CSOM to communicate with O365/SharePoint online. The rest of the coding is straightforward.


Wednesday, September 9, 2015

Authenticate to Office 365 and SharePoint Online option #1 - CSOM using SharePointOnlineCredentials object from C#


When working on SharePoint Online as a new developer, there is always some confusion how to connect and authenticate to the SharePoint site. I’m summarizing all the different authenticate ways so my developers could choice one appropriate approach for their projects.
 
In this blog, I’ll illustrate the CSOM C# example using SharePointOnlineCredentials object. In this case, you need to pass the user name and password. You need to add Microsoft.SharePoint.Client.dll and Microsoft.SharePoint.Client.Runtime.dll references.

 

using System;
using System.Security;
using Microsoft.SharePoint.Client;
 

namespace CSOM.Example
{
    class Program
    {

        static void Main(string[] args)
        { 

            // Site URL, user name, and password

            string webUrl = "https://mycompany.sharepoint.com/sites/SPDEV";

            string userName = "user@myconpony.com";

            string password = "password";
 

            // Convert the string passowrd to SecureString

            SecureString securePassword = new SecureString();

            foreach (char c in password)

            {

                securePassword.AppendChar(c);

            } 

 

            using (var context = new ClientContext(webUrl))

            {

                context.Credentials = new SharePointOnlineCredentials(userName, securePassword);

                context.Load(context.Web, w => w.Title);

                context.ExecuteQuery();

 

                Console.WriteLine("Your site title is: " + context.Web.Title); 

                var list = context.Web.Lists.GetByTitle("TestList");

                context.Load(list);

                context.ExecuteQuery();

                Console.WriteLine("Your list title is: " + list.Title);

                CamlQuery query = CamlQuery.CreateAllItemsQuery(100);

                ListItemCollection items = list.GetItems(query); 

                context.Load(items);

                context.ExecuteQuery();

                foreach (ListItem listItem in items)

                {

                    // We have all the list item data. For example, Title.

                    Console.WriteLine("Your item title is: " + listItem["Title"]);

                }

            }

        } 

    }

}

Thursday, September 3, 2015

Procedure to debug and fix error "This page can't be displayed" for provider-hosted SharePoint Add-ins

If you create an OoB provider-hosted SharePoint Add-in and run from Visual Studio, you should be able to see the default web page with “Welcome <your name>” on it.

However, we are getting the following error “This page can't be displayed” on all our development 2012 servers.


After extensive debugging, we have found a workaround for this issue and here are the steps to debug and fix it.

1. Verify TLS and SSL for browser are enabled as shown below for IE.



2. Verify the web app is inside IIS entry. The IIS configuration should be in this location C:\Users\harryc\Documents\IISExpress\config\applicationhost.xml. Check whether you have the application you developed in the configuration like below. 

 <site name="SharePointApp4Web" id="22">
                <application path="/" applicationPool="Clr4IntegratedAppPool">
                    <virtualDirectory path="/" physicalPath="C:\Projects\SharePoint2013\O365\DEV2013\SharePointApp4\SharePointApp4Web" />
                </application>
                <bindings>
                    <binding protocol="http" bindingInformation="*:44119:localhost" />
                    <binding protocol="https" bindingInformation="*:44304:localhost" />
                </bindings>
</site>


3. Verify Window system have any error as below.

In my case, the errors are:
A fatal error occurred when attempting to access the SSL server credential private key. The error code returned from the cryptographic module is 0x8009030D. The internal error state is 10001.

An error occurred while using SSL configuration for endpoint 0.0.0.0:44304.  The error status code is contained within the returned data.

4. Nest step is to verify the cert for the port number (44304) running the web. You should look at the Certificate Hash.

Run command with the port number the web is running:

IIS Cert netsh http show sslcert ipport=0.0.0.0:44304

    IP:port                      : 0.0.0.0:44304
    Certificate Hash             : ec4d6de883f60ab764f696e6a712f6694ec86b11
    Application ID               : {214124cd-d05b-4309-9af9-9caa44b2b74a}
    Certificate Store Name       : MY
    Verify Client Certificate Revocation : Enabled
    Verify Revocation Using Cached Client Certificate Only : Disabled
    Usage Check                  : Enabled
    Revocation Freshness Time    : 0
    URL Retrieval Timeout        : 0
    Ctl Identifier               : (null)
    Ctl Store Name               : (null)
    DS Mapper Usage              : Disabled
    Negotiate Client Certificate : Disabled

You can get the Certificate Hash and Application ID from above command. 

5. Verify cert on IIS directly.

You could also verify the certs to run the below command.

mmc.exe-File->Add/Remove Snapin..->Add Certificates->Select Computer account->Local Computer-OK.


Identify the certs the express 8 is using and right click Open->Details. Found the Thumprint value. This should match the value from netsh command line.

In my case, I'm getting following error "No keys found certificate!". You will understand why the provided-hosted app does not work. There is bad certificate.



We are not sure why the Visual Studio installation did not install/generate correct certificates for IIE 8 express. We are still working with Microsoft to isolate the root cause. The workaround is to change the certificate IIS Express runs against for a specific ip/port by manually deleting and re-adding the bindings via the command-line.

Here are the steps for your reference.

1. Create a self-signed certificate (i.e. “IISExpressTest”) on the server and make note of the Thumbprint value.
                Open IIS manager
                Click “Create Self-Signed Certificate…”
                Enter the name like IISExpressTest and keep Personal as store
                Right the Cert and click View
                View the details and copy the Thumbprint value like 
                    5cb2a108b853f372103294f74a12ddab0c549e6a for future step

2. From the command line do: 
netsh http show sslcert ipport=0.0.0.0:44304

    IP:port                      : 0.0.0.0:44304
    Certificate Hash             : ec4d6de883f60ab764f696e6a712f6694ec86b11
    Application ID               : {214124cd-d05b-4309-9af9-9caa44b2b74a}
    Certificate Store Name       : MY
    Verify Client Certificate Revocation : Enabled
    Verify Revocation Using Cached Client Certificate Only : Disabled
    Usage Check                  : Enabled
    Revocation Freshness Time    : 0
    URL Retrieval Timeout        : 0
    Ctl Identifier               : (null)
    Ctl Store Name               : (null)
    DS Mapper Usage              : Disabled
    Negotiate Client Certificate : Disabled
Record the Application ID for future step.

3. Determine what port a specific IIS Express site uses.  In my case, it was using 44304, so https://localhost:44304 was my site.

4. From the command line, delete the current cert.
netsh http delete sslcert ipport=0.0.0.0:44304

5. From the command line, bind the new cert.
netsh http add sslcert ipport=0.0.0.0:44304 appId={214124cd-d05b-4309-9af9-9caa44b2b74a} certhash=‎5cb2a108b853f372103294f74a12ddab0c549e6a

The port number is the port for your web running by IIS
The appId is the value you got from step #2
The certhash is the value from step #1

6. Verify https://localhost: 44304 will bring up the new certificate “IISExpressTest”.

Run the web again and you could verify the issue should be fixed and you can click the certs and view details that matches the Thumbprint value.

This workaround needs to be run for any web created and I’m thinking to add this to the Visual Studio prebuild scrip to automate the step.