Пример #1
0
        /// <summary>
        /// Returns a PnPConnection based on connecting using an existing token
        /// </summary>
        /// <param name="token">Token to connect with</param>
        /// <param name="tokenAudience">Indicator of <see cref="TokenAudience"/> indicating for which API this token is meant to be used</param>
        /// <param name="host">PowerShell Host environment in which the commands are being run</param>
        /// <param name="initializationType">Indicator of type <see cref="InitializationType"/> which indicates the method used to set up the connection. Used for gathering usage analytics.</param>
        /// <param name="url">Url of the SharePoint environment to connect to, if applicable. Leave NULL not to connect to a SharePoint environment.</param>
        /// <param name="clientContext">A SharePoint ClientContext to make available within this connection. Leave NULL to not connect to a SharePoint environment.</param>
        /// <param name="minimalHealthScore">Minimum health score that the SharePoint server should report before allowing requests to be executed on it. Scale of 0 to 10 where 0 is healthiest and 10 is least healthy. Leave NULL not to perform health checks on SharePoint.</param>
        /// <param name="pnpVersionTag">Identifier set on the SharePoint ClientContext as the ClientTag to identify the source of the requests to SharePoint. Leave NULL not to set it.</param>
        /// <param name="disableTelemetry">Boolean indicating if telemetry on the commands being executed should be disabled. Telemetry is enabled by default.</param>
        /// <returns><see cref="PnPConnection"/ instance which can be used to communicate with one of the supported APIs</returns>
        public static PnPConnection GetConnectionWithToken(GenericToken token,
                                                           TokenAudience tokenAudience,
                                                           PSHost host,
                                                           InitializationType initializationType,
                                                           PSCredential credentials,
                                                           string url = null,
                                                           ClientContext clientContext       = null,
                                                           int?minimalHealthScore            = null,
                                                           string pnpVersionTag              = null,
                                                           bool disableTelemetry             = false,
                                                           AzureEnvironment azureEnvironment = AzureEnvironment.Production)
        {
            var connection = new PnPConnection(host, initializationType, url, clientContext, new Dictionary <TokenAudience, GenericToken>(1)
            {
                { tokenAudience, token }
            }, minimalHealthScore, pnpVersionTag, disableTelemetry)
            {
                ConnectionMethod = ConnectionMethod.AccessToken,
                Tenant           = token.ParsedToken.Claims.FirstOrDefault(c => c.Type.Equals("tid", StringComparison.InvariantCultureIgnoreCase))?.Value,
                ClientId         = token.ParsedToken.Claims.FirstOrDefault(c => c.Type.Equals("appid", StringComparison.InvariantCultureIgnoreCase))?.Value,
                AzureEnvironment = azureEnvironment
            };

            connection.PSCredential = credentials;
            return(connection);
        }
 /// <summary>
 /// Factory method for creating SWT tokens.
 /// </summary>
 /// <param name="issuer">The entity issuing the token.</param>
 /// <param name="audience">The entity receiving the token.</param>
 /// <param name="expiresOnUtc">The expiry time for the token in UTC.</param>
 /// <param name="signingKey">The token signing key.</param>
 /// <returns>
 /// An instance of SimpleWebToken class.
 /// </returns>
 public static SimpleWebToken CreateToken(
     TokenIssuer issuer,
     TokenAudience audience,
     DateTime expiresOnUtc,
     byte[] signingKey)
 {
     return(CreateToken(issuer, audience, expiresOnUtc, null, signingKey));
 }
        /// <summary>
        /// Gets the role claims for the current principal.
        /// </summary>
        /// <param name="issuer"></param>
        /// <param name="audience"></param>
        private IEnumerable <Claim> GetRoleClaims(TokenIssuer issuer, TokenAudience audience)
        {
            IDictionary <TokenIssuer, IList <string> > issuerToRolesMapping;

            if (this.audienceIssuerRolesMapping.TryGetValue(audience, out issuerToRolesMapping))
            {
                IList <string> roles;
                if (issuerToRolesMapping.TryGetValue(issuer, out roles))
                {
                    IList <Claim> roleClaims = roles.Select(role => new Claim(HolMonClaimTypes.Role, role)).ToList();
                    return(roleClaims);
                }
            }

            return(new[] { new Claim(HolMonClaimTypes.Role, HolMonRoles.AnonymousAccessRole) });
        }
        /// <summary>
        /// Factory method for creating SWT tokens. Use this overload when there is a requirement
        /// to encode additional claims into the token.
        /// </summary>
        /// <param name="issuer">The entity issuing the token.</param>
        /// <param name="audience">The entity receiving the token.</param>
        /// <param name="expiresOnUtc">The expiry time for the token in UTC.</param>
        /// <param name="additionalClaims">
        /// Any additional claims to be included as part of the token.
        /// </param>
        /// <param name="signingKey">The token signing key.</param>
        /// <returns>
        /// An instance of SimpleWebToken class.
        /// </returns>
        public static SimpleWebToken CreateToken(
            TokenIssuer issuer,
            TokenAudience audience,
            DateTime expiresOnUtc,
            IEnumerable <Claim> additionalClaims,
            byte[] signingKey)
        {
            if (issuer == TokenIssuer.Unknown)
            {
                throw new ArgumentException(
                          "{0} is not not allowed as token issuer.".FormatInvariant(issuer.ToString()));
            }

            if (audience == TokenAudience.Unknown)
            {
                throw new ArgumentException(
                          "{0} is not allowed as token audience.".FormatInvariant(audience.ToString()));
            }

            if (signingKey == null || signingKey.Length == 0)
            {
                throw new ArgumentException("The signing key is not valid.");
            }

            var claims = new List <Claim>();

            if (additionalClaims != null)
            {
                claims.AddRange(additionalClaims);
            }

            var token = SimpleWebToken.Create(issuer.ToString(), audience.ToString(), expiresOnUtc, claims);

            token.SignToken(signingKey);
            return(token);
        }
Пример #5
0
        private (bool valid, string message) ValidateTokenForPermissions(GenericToken token, TokenAudience tokenAudience, string[] orRoles = null, string[] andRoles = null, TokenType tokenType = TokenType.All)
        {
            bool valid   = false;
            var  message = string.Empty;

            if (tokenType != TokenType.All && token.TokenType != tokenType)
            {
                throw new PSSecurityException($"Access to {tokenAudience} failed because the API requires {(tokenType == TokenType.Application ? "an" : "a")} {tokenType} token while you currently use {(token.TokenType == TokenType.Application ? "an" : "a")} {token.TokenType} token.");
            }
            var andRolesMatched = false;

            if (andRoles != null && andRoles.Length != 0)
            {
                // we have explicitely required roles
                andRolesMatched = andRoles.All(r => token.Roles.Contains(r));
            }
            else
            {
                andRolesMatched = true;
            }

            var orRolesMatched = false;

            if (orRoles != null && orRoles.Length != 0)
            {
                orRolesMatched = orRoles.Any(r => token.Roles.Contains(r));
            }
            else
            {
                orRolesMatched = true;
            }

            if (orRolesMatched && andRolesMatched)
            {
                valid = true;
            }

            if (orRoles != null || andRoles != null)
            {
                if (!valid)
                {                // Requested role was not part of the access token, throw an exception explaining which application registration is missing which role
                    if (!orRolesMatched)
                    {
                        message += "for one of the following roles: " + string.Join(", ", orRoles);
                    }
                    if (!andRolesMatched)
                    {
                        message += (message != string.Empty ? ", and " : ", ") + "for all of the following roles: " + string.Join(", ", andRoles);
                    }
                    throw new PSSecurityException($"Access to {tokenAudience} failed because the app registration {ClientId} in tenant {Tenant} is not granted {message}");
                }
            }
            return(valid, message);
        }
Пример #6
0
 /// <summary>
 /// Adds the provided token to the available tokens in the current connection
 /// </summary>
 /// <param name="tokenAudience">Audience the token is for</param>
 /// <param name="token">The token to add</param>
 internal void AddToken(TokenAudience tokenAudience, GenericToken token)
 {
     AccessTokens[tokenAudience] = token;
 }
Пример #7
0
        /// <summary>
        /// Tries to get a token for the provided audience
        /// </summary>
        /// <param name="tokenAudience">Audience to try to get a token for</param>
        /// <param name="orRoles">The specific roles to request access to (i.e. Group.ReadWrite.All). Optional, will use default groups assigned to clientId if not specified.</param>
        /// <returns><see cref="GenericToken"/> for the audience or NULL if unable to retrieve a token for the audience on the current connection</returns>
        internal GenericToken TryGetToken(TokenAudience tokenAudience, AzureEnvironment azureEnvironment, string[] orRoles = null, string[] andRoles = null, TokenType tokenType = TokenType.All)
        {
            GenericToken token = null;

            switch (tokenAudience)
            {
            case TokenAudience.MicrosoftGraph:

                if (ConnectionMethod == ConnectionMethod.DeviceLogin || ConnectionMethod == ConnectionMethod.GraphDeviceLogin)
                {
                    var officeManagementApiScopes = Enum.GetNames(typeof(OfficeManagementApiPermission)).Select(s => s.Replace("_", ".")).Intersect(Scopes).ToArray();
                    // Take the remaining scopes and try requesting them from the Microsoft Graph API
                    var scopes = Scopes.Except(officeManagementApiScopes).ToArray();
                    token = GraphToken.AcquireApplicationTokenDeviceLogin(PnPConnection.PnPManagementShellClientId, scopes, DeviceLoginCallback(null, false), AzureEnvironment);
                }
                else
                {
                    if (!string.IsNullOrEmpty(Tenant))
                    {
                        if (Certificate != null)
                        {
                            token = GraphToken.AcquireApplicationToken(Tenant, ClientId, Certificate, AzureEnvironment);
                        }
                        else if (ClientSecret != null)
                        {
                            token = GraphToken.AcquireApplicationToken(Tenant, ClientId, ClientSecret, AzureEnvironment);
                        }
                        else if (Scopes != null)
                        {
                            var officeManagementApiScopes = Enum.GetNames(typeof(OfficeManagementApiPermission)).Select(s => s.Replace("_", ".")).Intersect(Scopes).ToArray();
                            // Take the remaining scopes and try requesting them from the Microsoft Graph API
                            var scopes = Scopes.Except(officeManagementApiScopes).ToArray();
                            if (scopes.Length > 0)
                            {
                                token = PSCredential == null?GraphToken.AcquireApplicationTokenInteractive(PnPManagementShellClientId, scopes, azureEnvironment) : GraphToken.AcquireDelegatedTokenWithCredentials(PnPManagementShellClientId, scopes, PSCredential.UserName, PSCredential.Password, azureEnvironment);
                            }
                            else
                            {
                                throw new PSSecurityException($"Access to {tokenAudience} failed because you did not connect with any permission scopes related to this service (for instance 'Group.Read.All').");
                            }
                        }
                    }
                }
                break;

            case TokenAudience.OfficeManagementApi:
                if (!string.IsNullOrEmpty(Tenant))
                {
                    if (Certificate != null)
                    {
                        token = OfficeManagementApiToken.AcquireApplicationToken(Tenant, ClientId, Certificate, AzureEnvironment);
                    }
                    else if (ClientSecret != null)
                    {
                        token = OfficeManagementApiToken.AcquireApplicationToken(Tenant, ClientId, ClientSecret, AzureEnvironment);
                    }
                    else if (Scopes != null)
                    {
                        var scopes = Enum.GetNames(typeof(OfficeManagementApiPermission)).Select(s => s.Replace("_", ".")).Intersect(Scopes).ToArray();
                        // Take the remaining scopes and try requesting them from the Microsoft Graph API
                        if (scopes.Length > 0)
                        {
                            token = PSCredential == null?OfficeManagementApiToken.AcquireApplicationTokenInteractive(PnPManagementShellClientId, scopes, azureEnvironment) : OfficeManagementApiToken.AcquireDelegatedTokenWithCredentials(PnPManagementShellClientId, scopes, PSCredential.UserName, PSCredential.Password, azureEnvironment);
                        }
                        else
                        {
                            throw new PSSecurityException($"Access to {tokenAudience} failed because you did not connect with any permission scopes related to this service (for instance 'ServiceHealth.Read').");
                        }
                    }
                }
                break;

            case TokenAudience.SharePointOnline:
                // This is not a token type we can request on demand
                return(null);
            }

            if (token != null)
            {
                var validationResults = ValidateTokenForPermissions(token, tokenAudience, orRoles, andRoles, tokenType);
                if (!validationResults.valid)
                {
                    throw new PSSecurityException($"Access to {tokenAudience} failed because the app registration {ClientId} in tenant {Tenant} is not granted {validationResults.message}");
                }
                return(token);
            }

            // Didn't have a token yet and unable to retrieve one
            return(null);
        }
Пример #8
0
 /// <summary>
 /// Tries to get an access token for the provided audience
 /// </summary>
 /// <param name="tokenAudience">Audience to try to get an access token for</param>
 /// <param name="roles">The specific roles to request access to (i.e. Group.ReadWrite.All). Optional, will use default roles assigned to clientId if not specified.</param>
 /// <returns>AccessToken for the audience or NULL if unable to retrieve an access token for the audience on the current connection</returns>
 internal string TryGetAccessToken(TokenAudience tokenAudience, string[] roles = null)
 {
     return(TryGetToken(tokenAudience, AzureEnvironment, roles)?.AccessToken);
 }
Пример #9
0
        /// <summary>
        /// Tries to get a token for the provided audience
        /// </summary>
        /// <param name="tokenAudience">Audience to try to get a token for</param>
        /// <param name="orRoles">The specific roles to request access to (i.e. Group.ReadWrite.All). Optional, will use default groups assigned to clientId if not specified.</param>
        /// <returns><see cref="GenericToken"/> for the audience or NULL if unable to retrieve a token for the audience on the current connection</returns>
        internal GenericToken TryGetToken(TokenAudience tokenAudience, string[] orRoles = null, string[] andRoles = null, TokenType tokenType = TokenType.All)
        {
            GenericToken token = null;

            //Validate if we have a token already
            //if (AccessTokens.ContainsKey(tokenAudience))
            //{
            //    // We have a token already, ensure it is still valid
            //    token = AccessTokens[tokenAudience];

            //    if (token.ExpiresOn > DateTime.Now)
            //    {
            //        var validationResults = ValidateTokenForPermissions(token, tokenAudience, orRoles, andRoles, tokenType);
            //        if (validationResults.valid)
            //        {
            //            return token;
            //        }
            //        throw new PSSecurityException($"Access to {tokenAudience} failed because the app registration {ClientId} in tenant {Tenant} is not granted {validationResults.message}");
            //    }

            //    // Token was no longer valid, proceed with trying to create a new token
            //}

            // We do not have a token for the requested audience yet or it was no longer valid, try to create (a new) one
            switch (tokenAudience)
            {
            case TokenAudience.MicrosoftGraph:
                if (ConnectionMethod == ConnectionMethod.DeviceLogin || ConnectionMethod == ConnectionMethod.GraphDeviceLogin)
                {
                    token = GraphToken.AcquireApplicationTokenDeviceLogin(PnPConnection.DeviceLoginClientId, Scopes, DeviceLoginCallback(null, false));
                }
                else
                {
                    if (!string.IsNullOrEmpty(Tenant))
                    {
                        if (Certificate != null)
                        {
                            token = GraphToken.AcquireApplicationToken(Tenant, ClientId, Certificate);
                        }
                        else if (ClientSecret != null)
                        {
                            token = GraphToken.AcquireApplicationToken(Tenant, ClientId, ClientSecret);
                        }
                        else if (Scopes != null)
                        {
                            token = PSCredential == null?GraphToken.AcquireApplicationTokenInteractive(DeviceLoginClientId, Scopes) : GraphToken.AcquireDelegatedTokenWithCredentials(DeviceLoginClientId, Scopes, PSCredential.UserName, PSCredential.Password);
                        }
                    }
                }
                break;

            case TokenAudience.OfficeManagementApi:
                if (!string.IsNullOrEmpty(Tenant))
                {
                    if (Certificate != null)
                    {
                        token = OfficeManagementApiToken.AcquireApplicationToken(Tenant, ClientId, Certificate);
                    }
                    else if (ClientSecret != null)
                    {
                        token = OfficeManagementApiToken.AcquireApplicationToken(Tenant, ClientId, ClientSecret);
                    }
                }
                break;

            case TokenAudience.SharePointOnline:
                // This is not a token type we can request on demand
                return(null);
            }

            if (token != null)
            {
                var validationResults = ValidateTokenForPermissions(token, tokenAudience, orRoles, andRoles, tokenType);
                if (!validationResults.valid)
                {
                    throw new PSSecurityException($"Access to {tokenAudience} failed because the app registration {ClientId} in tenant {Tenant} is not granted {validationResults.message}");
                }
                // Managed to create a token for the requested audience, add it to our collection with tokens
                //AccessTokens[tokenAudience] = token;
                return(token);
            }

            // Didn't have a token yet and unable to retrieve one
            return(null);
        }
Пример #10
0
        /// <summary>
        /// Tries to get a token for the provided audience
        /// </summary>
        /// <param name="tokenAudience">Audience to try to get a token for</param>
        /// <param name="roles">The specific roles to request access to (i.e. Group.ReadWrite.All). Optional, will use default groups assigned to clientId if not specified.</param>
        /// <returns><see cref="GenericToken"/> for the audience or NULL if unable to retrieve a token for the audience on the current connection</returns>
        internal GenericToken TryGetToken(TokenAudience tokenAudience, string[] roles = null)
        {
            GenericToken token = null;

            // Validate if we have a token already
            if (AccessTokens.ContainsKey(tokenAudience))
            {
                // We have a token already, ensure it is still valid
                token = AccessTokens[tokenAudience];

                if (token.ExpiresOn > DateTime.Now)
                {
                    // Token is still valid, ensure we dont have specific roles to check for or the requested roles to execute the command are present in the token
                    if (roles == null || roles.Length == 0 || roles.Any(r => token.Roles.Contains(r)))
                    {
                        return(token);
                    }

                    if (roles != null)
                    {
                        // Requested role was not part of the access token, throw an exception explaining which application registration is missing which role
                        throw new PSSecurityException($"Access to {tokenAudience} failed because the app registration {ClientId} in tenant {Tenant} is not granted {(roles.Length != 1 ? "any of " : string.Empty)}the permission{(roles.Length != 1 ? "s" : string.Empty)} {string.Join(", ", roles).TrimEnd(new[] { ',', ' ' })}");
                    }
                }

                // Token was no longer valid, proceed with trying to create a new token
            }

            // We do not have a token for the requested audience yet or it was no longer valid, try to create (a new) one
            switch (tokenAudience)
            {
            case TokenAudience.MicrosoftGraph:
                if (!string.IsNullOrEmpty(Tenant))
                {
                    if (Certificate != null)
                    {
                        token = GraphToken.AcquireToken(Tenant, ClientId, Certificate);
                    }
                    else if (ClientSecret != null)
                    {
                        token = GraphToken.AcquireToken(Tenant, ClientId, ClientSecret);
                    }
                }
                break;

            case TokenAudience.OfficeManagementApi:
                if (!string.IsNullOrEmpty(Tenant))
                {
                    if (Certificate != null)
                    {
                        token = OfficeManagementApiToken.AcquireToken(Tenant, ClientId, Certificate);
                    }
                    else if (ClientSecret != null)
                    {
                        token = OfficeManagementApiToken.AcquireToken(Tenant, ClientId, ClientSecret);
                    }
                }
                break;

            case TokenAudience.SharePointOnline:
                // This is not a token type we can request on demand
                return(null);
            }

            if (token != null)
            {
                // Managed to create a token for the requested audience, add it to our collection with tokens
                AccessTokens[tokenAudience] = token;
                return(token);
            }

            // Didn't have a token yet and unable to retrieve one
            return(null);
        }