Skip to content
This repository has been archived by the owner on Jan 19, 2021. It is now read-only.

Commit

Permalink
Merge pull request #2088 from SharePoint/dev
Browse files Browse the repository at this point in the history
May 2019 Intermediate Release
  • Loading branch information
erwinvanhunen authored May 15, 2019
2 parents fc5b2ac + eff0bdb commit 0cad178
Show file tree
Hide file tree
Showing 17 changed files with 140 additions and 65 deletions.
Binary file modified Binaries/SharePointPnP.Modernization.Framework.dll
Binary file not shown.
Binary file modified Binaries/release/SharePointPnP.Modernization.Framework.dll
Binary file not shown.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).

## [3.10.1906.0 - June 2019 Release]
## [3.10.1905.1 - May 2019 Intermediate Release]

### Added

### Changed
- Updated core provisioning engine to handle a server side issue.
- Added support for certificte thumbprint login with ADAL and updated connection sample
- Added support for outputting .cer file from New-PnPAzureCertificate

### Deprecated
- Out parameter for New-PnPAzureCertificate replaced with OutPfx

### Contributors

Expand Down
28 changes: 27 additions & 1 deletion Commands/Base/ConnectOnline.cs

Large diffs are not rendered by default.

31 changes: 26 additions & 5 deletions Commands/Base/NewAzureCertificate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ Certificate contains the PEM encoded certificate.
PrivateKey contains the PEM encoded private key of the certificate.",
Category = CmdletHelpCategory.Base)]
[CmdletExample(
Code = @"PS:> New-PnPAzureCertificate",
Remarks = @"This will generate a default self-signed certificate named ""pnp.contoso.com"" valid for 10 years.",
Code = @"PS:> New-PnPAzureCertificate -OutPfx pnp.pfx -OutCert pnp.cer",
Remarks = @"This will generate a default self-signed certificate named ""pnp.contoso.com"" valid for 10 years and output a pfx and cer file.",
SortOrder = 1)]
[CmdletExample(
Code = @"PS:> New-PnPAzureCertificate -CommonName ""My Certificate"" -ValidYears 30 ",
Expand All @@ -48,9 +48,16 @@ public class NewPnPAdalCertificate : PSCmdlet
[Parameter(Mandatory = false, HelpMessage = "Organizational Unit Name (eg, section)", Position = 5)]
public string OrganizationUnit = string.Empty;

[Obsolete("Use OutPfx parameter")]
[Parameter(Mandatory = false, HelpMessage = "Filename to write to, optionally including full path (.pfx)", Position = 6)]
public string Out;

[Parameter(Mandatory = false, HelpMessage = "Filename to write to, optionally including full path (.pfx)", Position = 6)]
public string OutPfx;

[Parameter(Mandatory = false, HelpMessage = "Filename to write to, optionally including full path (.cer)", Position = 6)]
public string OutCert;

[Parameter(Mandatory = false, HelpMessage = "Number of years until expiration (default is 10, max is 30)", Position = 7)]
public int ValidYears = 10;

Expand Down Expand Up @@ -80,12 +87,26 @@ protected override void ProcessRecord()

if (!string.IsNullOrWhiteSpace(Out))
{
if (!Path.IsPathRooted(Out))
OutPfx = Out;
}
if (!string.IsNullOrWhiteSpace(OutPfx))
{
if (!Path.IsPathRooted(OutPfx))
{
Out = Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, Out);
OutPfx = Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, OutPfx);
}
byte[] certData = certificate.Export(X509ContentType.Pfx, CertificatePassword);
File.WriteAllBytes(Out, certData);
File.WriteAllBytes(OutPfx, certData);
}

if (!string.IsNullOrWhiteSpace(OutCert))
{
if (!Path.IsPathRooted(OutCert))
{
OutCert = Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, OutCert);
}
byte[] certData = certificate.Export(X509ContentType.Cert);
File.WriteAllBytes(OutCert, certData);
}

var rawCert = certificate.GetRawCertData();
Expand Down
30 changes: 26 additions & 4 deletions Commands/Base/SPOnlineConnectionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using SharePointPnP.PowerShell.Commands.Enums;
using System;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Net;
Expand All @@ -15,7 +14,6 @@
using OfficeDevPnP.Core.Utilities;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Net.Http;
using System.Security.Cryptography;
Expand Down Expand Up @@ -386,19 +384,40 @@ internal static SPOnlineConnection InitiateAzureADAppOnlyConnection(Uri url, str
return spoConnection;
}

internal static SPOnlineConnection InitiateAzureADAppOnlyConnection(Uri url, string clientId, string tenant,
string thumbprint, int minimalHealthScore,
int retryCount, int retryWait, int requestTimeout, string tenantAdminUrl, PSHost host,
bool disableTelemetry, bool skipAdminCheck = false,
AzureEnvironment azureEnvironment = AzureEnvironment.Production)
{
X509Certificate2 certificate = CertificateHelper.GetCertificatFromStore(thumbprint);
return InitiateAzureAdAppOnlyConnectionWithCert(url, clientId, tenant, minimalHealthScore, retryCount, retryWait, requestTimeout, tenantAdminUrl, host, disableTelemetry, skipAdminCheck, azureEnvironment, certificate);
}

internal static SPOnlineConnection InitiateAzureADAppOnlyConnection(Uri url, string clientId, string tenant, string certificatePEM, string privateKeyPEM, SecureString certificatePassword, int minimalHealthScore, int retryCount, int retryWait, int requestTimeout, string tenantAdminUrl, PSHost host, bool disableTelemetry, bool skipAdminCheck = false, AzureEnvironment azureEnvironment = AzureEnvironment.Production)
{
string password = new System.Net.NetworkCredential(string.Empty, certificatePassword).Password;
X509Certificate2 certificate = CertificateHelper.GetCertificateFromPEMstring(certificatePEM, privateKeyPEM, password);

return InitiateAzureAdAppOnlyConnectionWithCert(url, clientId, tenant, minimalHealthScore, retryCount, retryWait, requestTimeout, tenantAdminUrl, host, disableTelemetry, skipAdminCheck, azureEnvironment, certificate);
}

private static SPOnlineConnection InitiateAzureAdAppOnlyConnectionWithCert(Uri url, string clientId, string tenant,
int minimalHealthScore, int retryCount, int retryWait, int requestTimeout, string tenantAdminUrl, PSHost host, bool disableTelemetry,
bool skipAdminCheck, AzureEnvironment azureEnvironment, X509Certificate2 certificate)
{
var authManager = new OfficeDevPnP.Core.AuthenticationManager();
var clientContext = authManager.GetAzureADAppOnlyAuthenticatedContext(url.ToString(), clientId, tenant, certificate, azureEnvironment);
var clientContext =
authManager.GetAzureADAppOnlyAuthenticatedContext(url.ToString(), clientId, tenant, certificate,
azureEnvironment);
var context = PnPClientContext.ConvertFrom(clientContext, retryCount, retryWait * 1000);
context.RequestTimeout = requestTimeout;
var connectionType = ConnectionType.OnPrem;
if (url.Host.ToUpperInvariant().EndsWith("SHAREPOINT.COM"))
{
connectionType = ConnectionType.O365;
}

if (skipAdminCheck == false)
{
if (IsTenantAdminSite(context))
Expand All @@ -409,7 +428,10 @@ internal static SPOnlineConnection InitiateAzureADAppOnlyConnection(Uri url, str

CleanupCryptoMachineKey(certificate);

return new SPOnlineConnection(context, connectionType, minimalHealthScore, retryCount, retryWait, null, url.ToString(), tenantAdminUrl, PnPPSVersionTag, host, disableTelemetry, InitializationType.AADAppOnly);
var spoConnection = new SPOnlineConnection(context, connectionType, minimalHealthScore, retryCount, retryWait, null,
url.ToString(), tenantAdminUrl, PnPPSVersionTag, host, disableTelemetry, InitializationType.AADAppOnly);
spoConnection.ConnectionMethod = ConnectionMethod.AzureADAppOnly;
return spoConnection;
}

private static void CleanupCryptoMachineKey(X509Certificate2 certificate)
Expand Down
4 changes: 2 additions & 2 deletions Commands/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("3.9.1905.0")]
[assembly: AssemblyFileVersion("3.9.1905.0")]
[assembly: AssemblyVersion("3.9.1905.1")]
[assembly: AssemblyFileVersion("3.9.1905.1")]
[assembly: InternalsVisibleTo("SharePointPnP.PowerShell.Tests")]
30 changes: 30 additions & 0 deletions Commands/Utilities/CertificateHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,36 @@ internal static string CertificateToBase64(X509Certificate2 certificate, bool us
return sb.ToString();
}

internal static X509Certificate2 GetCertificatFromStore(string thumbprint)
{
List<StoreLocation> locations = new List<StoreLocation>
{
StoreLocation.CurrentUser,
StoreLocation.LocalMachine
};

foreach (var location in locations)
{
X509Store store = new X509Store("My", location);
try
{
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection certificates = store.Certificates.Find(
X509FindType.FindByThumbprint, thumbprint, false);
if (certificates.Count == 1)
{
return certificates[0];
}
}
finally
{
store.Close();
}
}

return null;
}

internal static X509Certificate2 GetCertificateFromPEMstring(string publicCert, string privateKey, string password)
{
if (string.IsNullOrWhiteSpace(password)) password = "";
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 23 additions & 51 deletions Samples/SharePoint.ConnectUsingAppPermissions/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ The PnP commandlets can use the Active Directory Authentication Library (ADAL) t

You are now ready to configure the Azure AD Application for invoking SharePoint Online with an App Only access token. In order to do that, you have to create and configure a self-signed X.509 certificate, which will be used to authenticate your Application against Azure AD, while requesting the App Only access token.

First of all, you have to create the self-signed X.509 Certificate, which can be created using the `New-PnPAzureCertificate` commandlet.

You may also add the `-Out` parameter if you want to save the certificate as a local .pfx file.
First of all, you have to create the self-signed X.509 Certificate, which can be created using the `New-PnPAzureCertificate` or `New-SelfSignedCertificate` commandlet. This tutorial uses `New-PnPAzureCertificate` for ease of use.

Create a self signed certificate using `New-PnPAzureCertificate` (output truncated for readability):

```PowerShell
$cert = New-PnPAzureCertificate
$cert = New-PnPAzureCertificate -OutPfx pnp.pfx -OutCert pnp.cer
$cert
Subject : CN=pnp.contoso.com
Expand All @@ -46,11 +44,12 @@ KeyCredentials :
Certificate : -----BEGIN CERTIFICATE-----MIICv...iqzrk=-----END CERTIFICATE-----
PrivateKey : -----BEGIN RSA PRIVATE KEY-----MIIEp...4W6g==-----END
RSA PRIVATE KEY-----
.\pnp.pfx #Install certificate
```

>For further details about the `New-PnPAzureCertificate` syntax and command line parameters you can read the documentation with `Get-Help New-PnPAzureCertificate -Detailed`. If you have an existing .pfx file you can get the PEM values and key credential manifest settings using `Get-PnPAzureCertificate`.
For the last line which installs the certificate pick either *Current User* or *Local Machine* and *Automatically select the certificate store based on the type of certificate*. This will place the certificate in the *my* store.

Both the certificate and the private key is outputted as PEM encoded strings. This is useful in automation where you can store the values as environmental variables or as strings in Azure Keyvault, instead of bundling the actual .pfx file itself.
>For further details about the `New-PnPAzureCertificate` syntax and command line parameters you can read the documentation with `Get-Help New-PnPAzureCertificate -Detailed`.
## Azure Active Directory Application registration
In order to connect to SharePoint Online using app-only permissions you have to **register an application in Azure Active Directory** linked to your Office 365 tenant. In order to do that, open Azure Active Directory Admin portal (https://aad.portal.azure.com) using the account of a user member of the Tenant Global Admins group.
Expand All @@ -68,84 +67,56 @@ your tenant. Click the "New application registraion" button in the upper left pa

![Azure AD - Add an Application - First Step](./Fig-03-Azure-AD-Add-Application-Step-01.png)

Provide a **name** for your application (we suggest to name it "SharePoint PnP CSOM Access"), select the option **"Web app / API"**, and fill in the **"Sign-on URL"** with the with a valid **URL**, for example _https://&lt;tenant&gt;.sharepoint.com/pnpcsom_. The URL does not have to exist, but it has to be valid. Click create when done.
Provide a **name** for your application (we suggest to name it "SharePoint PnP CSOM Access"), select the option **"Web"**. Click *Register* when done.

The newly created app registration will now be listed in your "App Registrations" list.
Open it and then click into settings and then Properties. You should now be at the following screen:
You should now be at the following screen:

![Azure AD - Add an Application - Third Step](./Fig-04-Azure-AD-Add-Application-Step-02.png)

Please make sure you :
- Copy the **Application ID** value as you'll need it later in the `ClientId` parameter when connecting to SharePoint Online.

Now, you should go back to the settings blade. Go into **Keys** where you'll create a Client Secret (used for app-only authentication). In order to do that, add a new security key (selecting 1 year, 2 years or never expires for key duration). Press the "Save" button in the lower part of the screen to generate the key value. After saving, you will see the key value. **Copy it in a safe place**, because you will not see it anymore.

>This key is not really needed when accessing SharePoint Online via CSOM, but if you access other API's using the same ADAL application you will need it. For example if you are creating Office 365 Groups using PnP PowerShell.
- Copy the **Application (client) ID** value as you'll need it later in the `ClientId` parameter when connecting to SharePoint Online.

![Azure AD - Create a client Secret](./Fig-05-Azure-AD-Add-AplicationSecret.png)

Now click on "Required Permissions", and click on the "Add" button, a new blade will appear.
Now click on "API Permissions" in the left menu, click on the "Add a permission" button, and pick SahrePoint in the pane which appears.

![Azure AD - Application - Required Permissions ](./Fig-06-Azure-AD-App-Config-02.png)

You need to configure the following permissions in order to get access to all resources:
* Office 365 SharePoint Online (**Application Permission**)
* **Have full control of all site collections**
* **Read and write managed metadata**
* **Read and write user profiles**
* **Sites.FullControl.All**
* **TermStore.ReadWrite.All**
* **User.ReadWriteAll**

You may of course opt in with less access as well. For further details, see the following figure.
You may of course opt in with less access as well.

![Azure AD - Application Configuration - Permissions Blade](./Fig-07-Azure-AD-App-Config-03.png)

The "Application Permissions" are those granted to the application when running as App Only. The other set of permissions, called "Delegated Permissions", defines the permissions granted to the application when running under a specific user's account delegation (using an app and user access token, from an OAuth 2.0 perspective).
The "Application permissions" are those granted to the application when running as App Only. The other set of permissions, called "Delegated permissions", defines the permissions granted to the application when running under a specific user's account delegation (using an app and user access token, from an OAuth 2.0 perspective).

Click the Grant Permission button on the 'Required Permissions' tab in order make the permissions effective. If you forget this, you will not be able to connect to SharePoint Online using the ADAL application.
Click the *Add permission* button when done and then clik the **Grant admin consent for &lt;tenant&gt;** button in order make the permissions effective. If you forget this last step, you will not be able to connect to SharePoint Online using the ADAL application.

<a name="apponlyazuread"></a>
### Update Azure AD Application manifest

From your generated certificate copy the key credentials which are to be added to the manifest of your ADAL application.

### Upload your client certificate

```PowerShell
$cert.KeyCredentials | clip
```

Go back to the Azure AD Application that you created in the previous step and click the **"Manifest"** button at the top of the blade, then click **Edit'**.
In order to update the manifest you need to upload the client certificate you generated in the beginning. Pick *Certificates & secrets* and *Upload certificate* where you upload `pnp.cer` previously generated (If you have an existing certificate in your certificate store you have to export a .cer file manually).

![Azure AD - Application Configuration - Manifest](./Fig-08-Azure-AD-App-Config-04.png)

Search for the **keyCredentials** property and replace it with the snippet you generated before, this will be similar to as seen on the figure above:

```JSON
"keyCredentials": [
{
"customKeyIdentifier": "<base64CertHash>",
"keyId": "<KeyId>",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": "<base64Cert>"
}
],
```

Click **Save** when you complete this step.
Please make sure you :
- Copy the **THUMBPRINT** value as you'll need it later in the `Thumbprint` parameter when connecting to SharePoint Online.

## Test the application using PnP
Using the application id and application password from the application registration you can
connect to the SharePoint Online using:

```PowerShell
> Connect-PnPOnline -PEMCertificate $cert.Certificate -PEMPrivateKey $cert.PrivateKey -Tenant contoso.onmicrosoft.com -ClientId e3b084e2-5b69-44ef-8bac-0592abfd123f -Url https://contoso.sharepoint.com
> Connect-PnPOnline -Tenant contoso.onmicrosoft.com -ClientId 68b3527b-cf40-4284-acb2-854cafcdbac4 -Thumbprint 34CFAA860E5FB8C44335A38A097C1E41EEA206AA -Url https://contoso.sharepoint.com
```

If you opted to save the certificate as a .pfx file you can connect using:
You can also connect using the .pfx directly if you did not install it using:

```PowerShell
> Connect-PnPOnline -CertificatePath .\mycert.pfx -Tenant contoso.onmicrosoft.com -ClientId e3b084e2-5b69-44ef-8bac-0
592abfd123f -Url https://contoso.sharepoint.com
> Connect-PnPOnline -CertificatePath c:\absolute-path\to\pnp.pfx -Tenant contoso.onmicrosoft.com -ClientId 68b3527b-cf40-4284-acb2-854cafcdbac4 -Url https://contoso.sharepoint.com
```

If all went as expected you should now be able get data from your site.
Expand Down Expand Up @@ -188,6 +159,7 @@ Mikael Svenson (Puzzlepart)
Version | Date | Comments
---------| -----| --------
1.0 | Feb 23 2018 | Initial release
2.0 | May 14 2019 | Updated to use new ADAL registration and upload of cer file

## **Disclaimer**
THIS CODE IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.9.1905.0
3.9.1905.1

0 comments on commit 0cad178

Please sign in to comment.