moved from ddf515b8
This commit is contained in:
parent
9edcce8858
commit
a9b826f8f5
@ -31,6 +31,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.19.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -26,21 +26,21 @@
|
||||
|
||||
global using System.Data;
|
||||
global using System.Diagnostics;
|
||||
global using System.Globalization;
|
||||
global using System.Net;
|
||||
global using System.Net.Http.Headers;
|
||||
global using System.Reflection;
|
||||
global using System.Runtime.Serialization;
|
||||
global using System.Security.Claims;
|
||||
global using System.Security.Cryptography;
|
||||
global using System.Security.Cryptography.Pkcs;
|
||||
global using System.Security.Cryptography.X509Certificates;
|
||||
global using System.Text;
|
||||
global using System.Text.Json.Serialization;
|
||||
global using System.Web;
|
||||
global using System.Xml.Linq;
|
||||
global using System.Xml.XPath;
|
||||
|
||||
global using ASC.Common;
|
||||
global using ASC.Common.Caching;
|
||||
global using ASC.Common.Log;
|
||||
global using ASC.Common.Utils;
|
||||
global using ASC.Core;
|
||||
global using ASC.Core.Common.Configuration;
|
||||
@ -54,15 +54,11 @@ global using ASC.FederatedLogin.Helpers;
|
||||
global using ASC.FederatedLogin.LoginProviders;
|
||||
global using ASC.FederatedLogin.Profile;
|
||||
global using ASC.Security.Cryptography;
|
||||
global using ASC.Web.Core.Files;
|
||||
|
||||
global using Autofac;
|
||||
|
||||
global using DotNetOpenAuth.Messaging;
|
||||
global using DotNetOpenAuth.OpenId;
|
||||
global using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
|
||||
global using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
|
||||
global using DotNetOpenAuth.OpenId.RelyingParty;
|
||||
global using JWT.Algorithms;
|
||||
global using JWT.Builder;
|
||||
|
||||
global using Microsoft.AspNetCore.Builder;
|
||||
global using Microsoft.AspNetCore.Hosting;
|
||||
@ -72,7 +68,10 @@ global using Microsoft.AspNetCore.WebUtilities;
|
||||
global using Microsoft.EntityFrameworkCore;
|
||||
global using Microsoft.Extensions.Caching.Memory;
|
||||
global using Microsoft.Extensions.Configuration;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
global using Microsoft.Extensions.Options;
|
||||
|
||||
global using Newtonsoft.Json;
|
||||
global using Newtonsoft.Json.Linq;
|
||||
|
||||
global using SecurityContext = ASC.Core.SecurityContext;
|
||||
|
197
common/ASC.FederatedLogin/LoginProviders/AppleIdLoginProvider.cs
Normal file
197
common/ASC.FederatedLogin/LoginProviders/AppleIdLoginProvider.cs
Normal file
@ -0,0 +1,197 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2021
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace ASC.FederatedLogin.LoginProviders;
|
||||
|
||||
[Scope]
|
||||
public class AppleIdLoginProvider : BaseLoginProvider<AppleIdLoginProvider>
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly RequestHelper _requestHelper;
|
||||
|
||||
public override string AccessTokenUrl { get { return "https://appleid.apple.com/auth/token"; } }
|
||||
public override string RedirectUri { get { return this["appleIdRedirectUrl"]; } }
|
||||
public override string ClientID { get { return (this["appleIdClientIdMobile"] != null && _httpContextAccessor?.HttpContext != null && _httpContextAccessor.HttpContext.Request.MobileApp()) ? this["appleIdClientIdMobile"] : this["appleIdClientId"]; } }
|
||||
public override string ClientSecret => GenerateSecret();
|
||||
public override string CodeUrl { get { return "https://appleid.apple.com/auth/authorize"; } }
|
||||
public override string Scopes { get { return ""; } }
|
||||
|
||||
public string TeamId { get { return this["appleIdTeamId"]; } }
|
||||
public string KeyId { get { return this["appleIdKeyId"]; } }
|
||||
public string PrivateKey { get { return this["appleIdPrivateKey"]; } }
|
||||
|
||||
public AppleIdLoginProvider() { }
|
||||
public AppleIdLoginProvider(
|
||||
OAuth20TokenHelper oAuth20TokenHelper,
|
||||
TenantManager tenantManager,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
CoreSettings coreSettings,
|
||||
IConfiguration configuration,
|
||||
ICacheNotify<ConsumerCacheItem> cache,
|
||||
ConsumerFactory consumerFactory,
|
||||
Signature signature,
|
||||
InstanceCrypto instanceCrypto,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
RequestHelper requestHelper,
|
||||
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
|
||||
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_requestHelper = requestHelper;
|
||||
}
|
||||
|
||||
public override LoginProfile ProcessAuthoriztion(HttpContext context, IDictionary<string, string> @params, IDictionary<string, string> additionalStateArgs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var token = Auth(context, Scopes, out var redirect, @params, additionalStateArgs);
|
||||
var claims = ValidateIdToken(JObject.Parse(token.OriginJson).Value<string>("id_token"));
|
||||
return GetProfileFromClaims(claims);
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return LoginProfile.FromError(Signature, InstanceCrypto, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public override LoginProfile GetLoginProfile(string authCode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(authCode))
|
||||
{
|
||||
throw new Exception("Login failed");
|
||||
}
|
||||
|
||||
var token = _oAuth20TokenHelper.GetAccessToken<AppleIdLoginProvider>(ConsumerFactory, authCode);
|
||||
var claims = ValidateIdToken(JObject.Parse(token.OriginJson).Value<string>("id_token"));
|
||||
return GetProfileFromClaims(claims);
|
||||
}
|
||||
public override LoginProfile GetLoginProfile(OAuth20Token token)
|
||||
{
|
||||
if (token == null)
|
||||
{
|
||||
throw new Exception("Login failed");
|
||||
}
|
||||
|
||||
var claims = ValidateIdToken(JObject.Parse(token.OriginJson).Value<string>("id_token"));
|
||||
return GetProfileFromClaims(claims);
|
||||
}
|
||||
|
||||
private LoginProfile GetProfileFromClaims(ClaimsPrincipal claims)
|
||||
{
|
||||
return new LoginProfile(Signature, InstanceCrypto)
|
||||
{
|
||||
Id = claims.FindFirst(ClaimTypes.NameIdentifier).Value,
|
||||
EMail = claims.FindFirst(ClaimTypes.Email)?.Value,
|
||||
Provider = ProviderConstants.AppleId,
|
||||
};
|
||||
}
|
||||
|
||||
private string GenerateSecret()
|
||||
{
|
||||
using (var cngKey = CngKey.Import(Convert.FromBase64String(PrivateKey), CngKeyBlobFormat.Pkcs8PrivateBlob))
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var token = handler.CreateJwtSecurityToken(
|
||||
issuer: TeamId,
|
||||
audience: "https://appleid.apple.com",
|
||||
subject: new ClaimsIdentity(new List<Claim> { new Claim("sub", ClientID) }),
|
||||
issuedAt: DateTime.UtcNow,
|
||||
notBefore: DateTime.UtcNow,
|
||||
expires: DateTime.UtcNow.AddMinutes(5),
|
||||
signingCredentials: new SigningCredentials(new ECDsaSecurityKey(new ECDsaCng(cngKey)), SecurityAlgorithms.EcdsaSha256)
|
||||
);
|
||||
token.Header.Add("kid", KeyId);
|
||||
|
||||
return handler.WriteToken(token);
|
||||
}
|
||||
}
|
||||
|
||||
private ClaimsPrincipal ValidateIdToken(string idToken)
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var claims = handler.ValidateToken(idToken, new TokenValidationParameters()
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKeys = GetApplePublicKeys(),
|
||||
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer = "https://appleid.apple.com",
|
||||
|
||||
ValidateAudience = true,
|
||||
ValidAudience = ClientID,
|
||||
|
||||
ValidateLifetime = true
|
||||
|
||||
}, out var _);
|
||||
|
||||
return claims;
|
||||
}
|
||||
|
||||
private IEnumerable<SecurityKey> GetApplePublicKeys()
|
||||
{
|
||||
var appplePublicKeys = _requestHelper.PerformRequest("https://appleid.apple.com/auth/keys");
|
||||
|
||||
var keys = new List<SecurityKey>();
|
||||
foreach (var webKey in JObject.Parse(appplePublicKeys).Value<JArray>("keys"))
|
||||
{
|
||||
var e = Base64UrlEncoder.DecodeBytes(webKey.Value<string>("e"));
|
||||
var n = Base64UrlEncoder.DecodeBytes(webKey.Value<string>("n"));
|
||||
|
||||
var key = new RsaSecurityKey(new RSAParameters { Exponent = e, Modulus = n })
|
||||
{
|
||||
KeyId = webKey.Value<string>("kid")
|
||||
};
|
||||
|
||||
keys.Add(key);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
}
|
@ -66,7 +66,7 @@ public abstract class BaseLoginProvider<T> : Consumer, ILoginProvider where T :
|
||||
internal readonly Signature Signature;
|
||||
internal readonly InstanceCrypto InstanceCrypto;
|
||||
|
||||
private readonly OAuth20TokenHelper _oAuth20TokenHelper;
|
||||
protected readonly OAuth20TokenHelper _oAuth20TokenHelper;
|
||||
|
||||
protected BaseLoginProvider() { }
|
||||
|
||||
@ -139,6 +139,16 @@ public abstract class BaseLoginProvider<T> : Consumer, ILoginProvider where T :
|
||||
|
||||
return _oAuth20TokenHelper.GetAccessToken<T>(ConsumerFactory, code);
|
||||
}
|
||||
|
||||
public virtual LoginProfile GetLoginProfile(OAuth20Token token)
|
||||
{
|
||||
return GetLoginProfile(token.AccessToken);
|
||||
}
|
||||
|
||||
public OAuth20Token GetToken(string codeOAuth)
|
||||
{
|
||||
return _oAuth20TokenHelper.GetAccessToken<T>(ConsumerFactory, codeOAuth);
|
||||
}
|
||||
}
|
||||
|
||||
public static class BaseLoginProviderExtension
|
||||
|
@ -29,9 +29,10 @@ namespace ASC.FederatedLogin.LoginProviders;
|
||||
[Scope]
|
||||
public class BitlyLoginProvider : Consumer, IValidateKeysProvider
|
||||
{
|
||||
private string BitlyClientId => this["bitlyClientId"];
|
||||
private string BitlyClientSecret => this["bitlyClientSecret"];
|
||||
private string BitlyUrl => this["bitlyUrl"];
|
||||
private string BitlyToken => this["bitlyToken"];
|
||||
|
||||
private readonly string _bitlyUrl = "https://api-ssl.bitly.com/v4/shorten";
|
||||
private readonly RequestHelper _requestHelper;
|
||||
|
||||
public BitlyLoginProvider() { }
|
||||
|
||||
@ -42,9 +43,11 @@ public class BitlyLoginProvider : Consumer, IValidateKeysProvider
|
||||
IConfiguration configuration,
|
||||
ICacheNotify<ConsumerCacheItem> cache,
|
||||
ConsumerFactory consumerFactory,
|
||||
RequestHelper requestHelper,
|
||||
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
|
||||
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, name, order, props, additional)
|
||||
{
|
||||
_requestHelper = requestHelper;
|
||||
}
|
||||
|
||||
public bool ValidateKeys()
|
||||
@ -63,35 +66,25 @@ public class BitlyLoginProvider : Consumer, IValidateKeysProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
return !string.IsNullOrEmpty(BitlyClientId) &&
|
||||
!string.IsNullOrEmpty(BitlyClientSecret) &&
|
||||
!string.IsNullOrEmpty(BitlyUrl);
|
||||
return !string.IsNullOrEmpty(BitlyToken);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetShortenLink(string shareLink)
|
||||
{
|
||||
var uri = new Uri(shareLink);
|
||||
|
||||
var bitly = string.Format(BitlyUrl, BitlyClientId, BitlyClientSecret, Uri.EscapeDataString(uri.ToString()));
|
||||
XDocument response;
|
||||
try
|
||||
var data = string.Format("{{\"long_url\":\"{0}\"}}", shareLink);
|
||||
var headers = new Dictionary<string, string>
|
||||
{
|
||||
response = XDocument.Load(bitly);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(e.Message, e);
|
||||
}
|
||||
{"Authorization" ,"Bearer " + BitlyToken}
|
||||
};
|
||||
|
||||
var status = response.XPathSelectElement("/response/status_code").Value;
|
||||
if (status != ((int)HttpStatusCode.OK).ToString(CultureInfo.InvariantCulture))
|
||||
{
|
||||
throw new InvalidOperationException(status);
|
||||
}
|
||||
var response = _requestHelper.PerformRequest(_bitlyUrl, "application/json", "POST", data, headers);
|
||||
|
||||
var data = response.XPathSelectElement("/response/data/url");
|
||||
var parser = JObject.Parse(response);
|
||||
if (parser == null) return null;
|
||||
|
||||
return data.Value;
|
||||
var link = parser.Value<string>("link");
|
||||
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
@ -24,24 +24,25 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using SecurityContext = ASC.Core.SecurityContext;
|
||||
|
||||
namespace ASC.Web.Studio.Core;
|
||||
|
||||
[Scope]
|
||||
public class EncryptionLoginProvider
|
||||
{
|
||||
private readonly ILogger<EncryptionLoginProvider> _logger;
|
||||
private readonly SecurityContext _securityContext;
|
||||
private readonly Signature _signature;
|
||||
private readonly InstanceCrypto _instanceCrypto;
|
||||
private readonly IOptionsSnapshot<AccountLinker> _snapshot;
|
||||
|
||||
public EncryptionLoginProvider(
|
||||
ILogger<EncryptionLoginProvider> logger,
|
||||
SecurityContext securityContext,
|
||||
Signature signature,
|
||||
InstanceCrypto instanceCrypto,
|
||||
IOptionsSnapshot<AccountLinker> snapshot)
|
||||
{
|
||||
_logger = logger;
|
||||
_securityContext = securityContext;
|
||||
_signature = signature;
|
||||
_instanceCrypto = instanceCrypto;
|
||||
@ -80,8 +81,15 @@ public class EncryptionLoginProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
var keys = _instanceCrypto.Decrypt(profile.Name);
|
||||
|
||||
return keys;
|
||||
try
|
||||
{
|
||||
return _instanceCrypto.Decrypt(profile.Name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = string.Format("Can not decrypt {0} keys for {1}", ProviderConstants.Encryption, userId);
|
||||
_logger.ErrorWithException(message, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,9 @@ public class GosUslugiLoginProvider : BaseLoginProvider<GosUslugiLoginProvider>
|
||||
|
||||
public override LoginProfile GetLoginProfile(string accessToken)
|
||||
{
|
||||
var tokenPayloadString = JsonWebToken.Decode(accessToken, string.Empty, false, true);
|
||||
var tokenPayloadString = JwtBuilder.Create()
|
||||
.WithAlgorithm(new HMACSHA256Algorithm())
|
||||
.Decode(accessToken);
|
||||
var tokenPayload = JObject.Parse(tokenPayloadString);
|
||||
if (tokenPayload == null)
|
||||
{
|
||||
|
@ -31,6 +31,10 @@ public interface ILoginProvider : IOAuthProvider
|
||||
LoginProfile ProcessAuthoriztion(HttpContext context, IDictionary<string, string> @params, IDictionary<string, string> additionalStateArgs);
|
||||
|
||||
LoginProfile GetLoginProfile(string accessToken);
|
||||
|
||||
LoginProfile GetLoginProfile(OAuth20Token token);
|
||||
|
||||
OAuth20Token GetToken(string codeOAuth);
|
||||
}
|
||||
|
||||
public interface IOAuthProvider
|
||||
|
@ -0,0 +1,109 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2021
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.FederatedLogin.LoginProviders;
|
||||
|
||||
public class MicrosoftLoginProvider : BaseLoginProvider<MicrosoftLoginProvider>
|
||||
{
|
||||
private const string MicrosoftProfileUrl = "https://graph.microsoft.com/oidc/userinfo";
|
||||
|
||||
public override string AccessTokenUrl { get { return "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"; } }
|
||||
public override string RedirectUri { get { return this["microsoftRedirectUrl"]; } }
|
||||
public override string ClientID { get { return this["microsoftClientId"]; } }
|
||||
public override string ClientSecret { get { return this["microsoftClientSecret"]; } }
|
||||
public override string CodeUrl { get { return "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize"; } }
|
||||
public override string Scopes { get { return "openid,email,profile"; } }
|
||||
|
||||
private readonly RequestHelper _requestHelper;
|
||||
|
||||
public MicrosoftLoginProvider() { }
|
||||
public MicrosoftLoginProvider(
|
||||
OAuth20TokenHelper oAuth20TokenHelper,
|
||||
TenantManager tenantManager,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
CoreSettings coreSettings,
|
||||
IConfiguration configuration,
|
||||
ICacheNotify<ConsumerCacheItem> cache,
|
||||
ConsumerFactory consumerFactory,
|
||||
Signature signature,
|
||||
InstanceCrypto instanceCrypto,
|
||||
RequestHelper requestHelper,
|
||||
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
|
||||
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
|
||||
{
|
||||
_requestHelper = requestHelper;
|
||||
}
|
||||
|
||||
public override LoginProfile GetLoginProfile(string accessToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(accessToken))
|
||||
{
|
||||
throw new Exception("Login failed");
|
||||
}
|
||||
|
||||
return RequestProfile(accessToken);
|
||||
}
|
||||
|
||||
private LoginProfile RequestProfile(string accessToken)
|
||||
{
|
||||
var openidProfile = _requestHelper.PerformRequest(MicrosoftProfileUrl, headers: new Dictionary<string, string>() { { "Authorization", "Bearer " + accessToken } });
|
||||
var loginProfile = ProfileFromMicrosoft(openidProfile);
|
||||
return loginProfile;
|
||||
}
|
||||
|
||||
internal LoginProfile ProfileFromMicrosoft(string openidProfile)
|
||||
{
|
||||
var jProfile = JObject.Parse(openidProfile);
|
||||
if (jProfile == null) throw new Exception("Failed to correctly process the response");
|
||||
|
||||
var profile = new LoginProfile(Signature, InstanceCrypto)
|
||||
{
|
||||
FirstName = jProfile.Value<string>("given_name"),
|
||||
LastName = jProfile.Value<string>("family_name"),
|
||||
EMail = jProfile.Value<string>("email"),
|
||||
Id = jProfile.Value<string>("sub"),
|
||||
Provider = ProviderConstants.Microsoft
|
||||
};
|
||||
|
||||
return profile;
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.FederatedLogin.LoginProviders;
|
||||
|
||||
class OpenIdLoginProvider : ILoginProvider
|
||||
{
|
||||
public string Scopes => string.Empty;
|
||||
public string CodeUrl => string.Empty;
|
||||
public string AccessTokenUrl => string.Empty;
|
||||
public string RedirectUri => string.Empty;
|
||||
public string ClientID => string.Empty;
|
||||
public string ClientSecret => string.Empty;
|
||||
public bool IsEnabled => _consumerFactory.Get<GoogleLoginProvider>().IsEnabled;
|
||||
|
||||
private static readonly OpenIdRelyingParty _openId = new OpenIdRelyingParty();
|
||||
private readonly Signature _signature;
|
||||
private readonly InstanceCrypto _instanceCrypto;
|
||||
private readonly ConsumerFactory _consumerFactory;
|
||||
|
||||
public OpenIdLoginProvider(Signature signature, InstanceCrypto instanceCrypto, ConsumerFactory consumerFactory)
|
||||
{
|
||||
_signature = signature;
|
||||
_instanceCrypto = instanceCrypto;
|
||||
_consumerFactory = consumerFactory;
|
||||
}
|
||||
|
||||
public LoginProfile ProcessAuthoriztion(HttpContext context, IDictionary<string, string> @params, IDictionary<string, string> additionalStateArgs)
|
||||
{
|
||||
var response = _openId.GetResponse();
|
||||
if (response == null)
|
||||
{
|
||||
if (Identifier.TryParse(@params["oid"], out var id))
|
||||
{
|
||||
try
|
||||
{
|
||||
IAuthenticationRequest request;
|
||||
|
||||
var realmUrlString = string.Empty;
|
||||
|
||||
@params.TryGetValue("realmUrl", out realmUrlString);
|
||||
|
||||
if (!string.IsNullOrEmpty(realmUrlString))
|
||||
{
|
||||
request = _openId.CreateRequest(id, new Realm(realmUrlString));
|
||||
}
|
||||
else
|
||||
{
|
||||
request = _openId.CreateRequest(id);
|
||||
}
|
||||
|
||||
request.AddExtension(new ClaimsRequest
|
||||
{
|
||||
Email = DemandLevel.Require,
|
||||
Nickname = DemandLevel.Require,
|
||||
Country = DemandLevel.Request,
|
||||
Gender = DemandLevel.Request,
|
||||
PostalCode = DemandLevel.Request,
|
||||
TimeZone = DemandLevel.Request,
|
||||
FullName = DemandLevel.Request,
|
||||
|
||||
|
||||
});
|
||||
var fetch = new FetchRequest();
|
||||
fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
|
||||
//Duplicating attributes
|
||||
fetch.Attributes.AddRequired("http://schema.openid.net/contact/email");//Add two more
|
||||
fetch.Attributes.AddRequired("http://openid.net/schema/contact/email");
|
||||
fetch.Attributes.AddRequired(WellKnownAttributes.Name.Alias);
|
||||
fetch.Attributes.AddRequired(WellKnownAttributes.Name.First);
|
||||
fetch.Attributes.AddRequired(WellKnownAttributes.Media.Images.Default);
|
||||
fetch.Attributes.AddRequired(WellKnownAttributes.Name.Last);
|
||||
fetch.Attributes.AddRequired(WellKnownAttributes.Name.Middle);
|
||||
fetch.Attributes.AddRequired(WellKnownAttributes.Person.Gender);
|
||||
fetch.Attributes.AddRequired(WellKnownAttributes.BirthDate.WholeBirthDate);
|
||||
request.AddExtension(fetch);
|
||||
request.RedirectToProvider();
|
||||
//context.Response.End();//TODO This will throw thread abort
|
||||
|
||||
}
|
||||
catch (ProtocolException ex)
|
||||
{
|
||||
return LoginProfile.FromError(_signature, _instanceCrypto, ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return LoginProfile.FromError(_signature, _instanceCrypto, new Exception("invalid OpenID identifier"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stage 3: OpenID Provider sending assertion response
|
||||
switch (response.Status)
|
||||
{
|
||||
case AuthenticationStatus.Authenticated:
|
||||
var spprofile = response.GetExtension<ClaimsResponse>();
|
||||
var fetchprofile = response.GetExtension<FetchResponse>();
|
||||
|
||||
var realmUrlString = string.Empty;
|
||||
@params.TryGetValue("realmUrl", out realmUrlString);
|
||||
|
||||
var profile = ProfileFromOpenId(spprofile, fetchprofile, response.ClaimedIdentifier.ToString(), realmUrlString);
|
||||
return profile;
|
||||
case AuthenticationStatus.Canceled:
|
||||
return LoginProfile.FromError(_signature, _instanceCrypto, new Exception("Canceled at provider"));
|
||||
case AuthenticationStatus.Failed:
|
||||
return LoginProfile.FromError(_signature, _instanceCrypto, response.Exception);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public LoginProfile GetLoginProfile(string accessToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal LoginProfile ProfileFromOpenId(ClaimsResponse spprofile, FetchResponse fetchprofile, string claimedId, string realmUrlString)
|
||||
{
|
||||
var profile = new LoginProfile(_signature, _instanceCrypto)
|
||||
{
|
||||
Link = claimedId,
|
||||
Id = claimedId,
|
||||
Provider = ProviderConstants.OpenId,
|
||||
};
|
||||
if (spprofile != null)
|
||||
{
|
||||
//Fill
|
||||
profile.BirthDay = spprofile.BirthDateRaw;
|
||||
profile.DisplayName = spprofile.FullName;
|
||||
profile.EMail = spprofile.Email;
|
||||
profile.Name = spprofile.Nickname;
|
||||
profile.Gender = spprofile.Gender.HasValue ? spprofile.Gender.Value.ToString() : "";
|
||||
profile.TimeZone = spprofile.TimeZone;
|
||||
profile.Locale = spprofile.Language;
|
||||
}
|
||||
if (fetchprofile != null)
|
||||
{
|
||||
profile.Name = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.Alias);
|
||||
profile.LastName = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.Last);
|
||||
profile.FirstName = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.First);
|
||||
profile.DisplayName = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.FullName);
|
||||
profile.MiddleName = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.Middle);
|
||||
profile.Salutation = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.Prefix);
|
||||
profile.Avatar = fetchprofile.GetAttributeValue(WellKnownAttributes.Media.Images.Default);
|
||||
profile.EMail = fetchprofile.GetAttributeValue(WellKnownAttributes.Contact.Email);
|
||||
profile.Gender = fetchprofile.GetAttributeValue(WellKnownAttributes.Person.Gender);
|
||||
profile.BirthDay = fetchprofile.GetAttributeValue(WellKnownAttributes.BirthDate.WholeBirthDate);
|
||||
}
|
||||
profile.RealmUrl = realmUrlString;
|
||||
|
||||
return profile;
|
||||
}
|
||||
}
|
@ -64,9 +64,7 @@ public class ProviderManager
|
||||
|
||||
public ILoginProvider GetLoginProvider(string providerType)
|
||||
{
|
||||
return providerType == ProviderConstants.OpenId
|
||||
? new OpenIdLoginProvider(_signature, _instanceCrypto, _consumerFactory)
|
||||
: _consumerFactory.GetByKey(providerType) as ILoginProvider;
|
||||
return _consumerFactory.GetByKey(providerType) as ILoginProvider;
|
||||
}
|
||||
|
||||
public LoginProfile Process(string providerType, HttpContext context, IDictionary<string, string> @params, IDictionary<string, string> additionalStateArgs = null)
|
||||
@ -74,7 +72,7 @@ public class ProviderManager
|
||||
return GetLoginProvider(providerType).ProcessAuthoriztion(context, @params, additionalStateArgs);
|
||||
}
|
||||
|
||||
public LoginProfile GetLoginProfile(string providerType, string accessToken)
|
||||
public LoginProfile GetLoginProfile(string providerType, string accessToken = null, string codeOAuth = null)
|
||||
{
|
||||
var consumer = GetLoginProvider(providerType);
|
||||
if (consumer == null)
|
||||
@ -84,6 +82,10 @@ public class ProviderManager
|
||||
|
||||
try
|
||||
{
|
||||
if (accessToken == null && codeOAuth != null)
|
||||
{
|
||||
return consumer.GetLoginProfile(consumer.GetToken(codeOAuth));
|
||||
}
|
||||
return consumer.GetLoginProfile(accessToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -24,18 +24,28 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Globalization;
|
||||
//using System.Web;
|
||||
|
||||
//using ASC.FederatedLogin.Profile;
|
||||
|
||||
//using Microsoft.AspNetCore.Http;
|
||||
//using Newtonsoft.Json.Linq;
|
||||
|
||||
//using Tweetinvi;
|
||||
//using Tweetinvi.Auth;
|
||||
//using Tweetinvi.Parameters;
|
||||
|
||||
//namespace ASC.FederatedLogin.LoginProviders
|
||||
//{
|
||||
// public class TwitterLoginProvider : BaseLoginProvider<TwitterLoginProvider>
|
||||
// {
|
||||
// public string TwitterKey { get { return Instance.ClientID; } }
|
||||
// public string TwitterSecret { get { return Instance.ClientSecret; } }
|
||||
// public string TwitterDefaultAccessToken { get { return Instance["twitterAccessToken_Default"]; } }
|
||||
// public string TwitterAccessTokenSecret { get { return Instance["twitterAccessTokenSecret_Default"]; } }
|
||||
// public static string TwitterKey { get { return Instance.ClientID; } }
|
||||
// public static string TwitterSecret { get { return Instance.ClientSecret; } }
|
||||
// public static string TwitterDefaultAccessToken { get { return Instance["twitterAccessToken_Default"]; } }
|
||||
// public static string TwitterAccessTokenSecret { get { return Instance["twitterAccessTokenSecret_Default"]; } }
|
||||
|
||||
// public override string AccessTokenUrl { get { return "https://api.twitter.com/oauth/access_token"; } }
|
||||
// public override string RedirectUri { get { return this["twitterRedirectUrl"]; } }
|
||||
@ -43,6 +53,8 @@
|
||||
// public override string ClientSecret { get { return this["twitterSecret"]; } }
|
||||
// public override string CodeUrl { get { return "https://api.twitter.com/oauth/request_token"; } }
|
||||
|
||||
// private static readonly IAuthenticationRequestStore _myAuthRequestStore = new LocalAuthenticationRequestStore();
|
||||
|
||||
// public override bool IsEnabled
|
||||
// {
|
||||
// get
|
||||
@ -57,39 +69,75 @@
|
||||
|
||||
// public override LoginProfile ProcessAuthoriztion(HttpContext context, IDictionary<string, string> @params)
|
||||
// {
|
||||
// if (!string.IsNullOrEmpty(context.Request.Query["denied"]))
|
||||
// if (!string.IsNullOrEmpty(context.Request["denied"]))
|
||||
// {
|
||||
// return LoginProfile.FromError(new Exception("Canceled at provider"));
|
||||
// }
|
||||
|
||||
// if (string.IsNullOrEmpty(context.Request.Query["oauth_token"]))
|
||||
// var appClient = new TwitterClient(TwitterKey, TwitterSecret);
|
||||
|
||||
// if (string.IsNullOrEmpty(context.Request["oauth_token"]))
|
||||
// {
|
||||
// var callbackAddress = new UriBuilder(RedirectUri)
|
||||
// {
|
||||
// Query = "state=" + HttpUtility.UrlEncode(context.Request.GetUrlRewriter().AbsoluteUri)
|
||||
// };
|
||||
|
||||
// var reqToken = OAuthUtility.GetRequestToken(TwitterKey, TwitterSecret, callbackAddress.ToString());
|
||||
// var url = OAuthUtility.BuildAuthorizationUri(reqToken.Token).ToString();
|
||||
// context.Response.Redirect(url, true);
|
||||
// var authenticationRequestId = Guid.NewGuid().ToString();
|
||||
|
||||
// // Add the user identifier as a query parameters that will be received by `ValidateTwitterAuth`
|
||||
// var redirectURL = _myAuthRequestStore.AppendAuthenticationRequestIdToCallbackUrl(callbackAddress.ToString(), authenticationRequestId);
|
||||
|
||||
// // Initialize the authentication process
|
||||
// var authenticationRequestToken = appClient.Auth.RequestAuthenticationUrlAsync(redirectURL)
|
||||
// .ConfigureAwait(false)
|
||||
// .GetAwaiter()
|
||||
// .GetResult();
|
||||
|
||||
// // Store the token information in the store
|
||||
// _myAuthRequestStore.AddAuthenticationTokenAsync(authenticationRequestId, authenticationRequestToken)
|
||||
// .ConfigureAwait(false)
|
||||
// .GetAwaiter()
|
||||
// .GetResult();
|
||||
|
||||
// context.Response.Redirect(authenticationRequestToken.AuthorizationURL, true);
|
||||
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// var requestToken = context.Request.Query["oauth_token"];
|
||||
// var pin = context.Request.Query["oauth_verifier"];
|
||||
// // Extract the information from the redirection url
|
||||
// var requestParameters = RequestCredentialsParameters.FromCallbackUrlAsync(context.Request.RawUrl, _myAuthRequestStore).GetAwaiter().GetResult();
|
||||
// // Request Twitter to generate the credentials.
|
||||
// var userCreds = appClient.Auth.RequestCredentialsAsync(requestParameters)
|
||||
// .ConfigureAwait(false)
|
||||
// .GetAwaiter()
|
||||
// .GetResult();
|
||||
|
||||
// var tokens = OAuthUtility.GetAccessToken(TwitterKey, TwitterSecret, requestToken, pin);
|
||||
// // Congratulations the user is now authenticated!
|
||||
// var userClient = new TwitterClient(userCreds);
|
||||
|
||||
// var accesstoken = new OAuthTokens
|
||||
// var user = userClient.Users.GetAuthenticatedUserAsync()
|
||||
// .ConfigureAwait(false)
|
||||
// .GetAwaiter()
|
||||
// .GetResult();
|
||||
|
||||
// var userSettings = userClient.AccountSettings.GetAccountSettingsAsync()
|
||||
// .ConfigureAwait(false)
|
||||
// .GetAwaiter()
|
||||
// .GetResult();
|
||||
|
||||
// return user == null
|
||||
// ? null
|
||||
// : new LoginProfile
|
||||
// {
|
||||
// AccessToken = tokens.Token,
|
||||
// AccessTokenSecret = tokens.TokenSecret,
|
||||
// ConsumerKey = TwitterKey,
|
||||
// ConsumerSecret = TwitterSecret
|
||||
// Name = user.Name,
|
||||
// DisplayName = user.ScreenName,
|
||||
// Avatar = user.ProfileImageUrl,
|
||||
// Locale = userSettings.Language.ToString(),
|
||||
// Id = user.Id.ToString(CultureInfo.InvariantCulture),
|
||||
// Provider = ProviderConstants.Twitter
|
||||
// };
|
||||
|
||||
// var account = TwitterAccount.VerifyCredentials(accesstoken).ResponseObject;
|
||||
// return ProfileFromTwitter(account);
|
||||
// }
|
||||
|
||||
// protected override OAuth20Token Auth(HttpContext context, string scopes, Dictionary<string, string> additional = null)
|
||||
@ -102,18 +150,16 @@
|
||||
// throw new NotImplementedException();
|
||||
// }
|
||||
|
||||
// internal static LoginProfile ProfileFromTwitter(TwitterUser twitterUser)
|
||||
// internal static LoginProfile ProfileFromTwitter(string twitterProfile)
|
||||
// {
|
||||
// return twitterUser == null
|
||||
// ? null
|
||||
// : new LoginProfile
|
||||
// var jProfile = JObject.Parse(twitterProfile);
|
||||
// if (jProfile == null) throw new Exception("Failed to correctly process the response");
|
||||
|
||||
// return new LoginProfile
|
||||
// {
|
||||
// Name = twitterUser.Name,
|
||||
// DisplayName = twitterUser.ScreenName,
|
||||
// Avatar = twitterUser.ProfileImageSecureLocation,
|
||||
// TimeZone = twitterUser.TimeZone,
|
||||
// Locale = twitterUser.Language,
|
||||
// Id = twitterUser.Id.ToString(CultureInfo.InvariantCulture),
|
||||
// DisplayName = jProfile.Value<string>("name"),
|
||||
// Locale = jProfile.Value<string>("lang"),
|
||||
// Id = jProfile.Value<string>("id"),
|
||||
// Provider = ProviderConstants.Twitter
|
||||
// };
|
||||
// }
|
||||
|
@ -1,66 +0,0 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.FederatedLogin.LoginProviders;
|
||||
|
||||
[Scope]
|
||||
public class YahooLoginProvider : BaseLoginProvider<YahooLoginProvider>
|
||||
{
|
||||
public const string YahooUrlUserGuid = "https://social.yahooapis.com/v1/me/guid";
|
||||
public const string YahooUrlContactsFormat = "https://social.yahooapis.com/v1/user/{0}/contacts";
|
||||
|
||||
public override string CodeUrl => "https://api.login.yahoo.com/oauth2/request_auth";
|
||||
public override string AccessTokenUrl => "https://api.login.yahoo.com/oauth2/get_token";
|
||||
public override string RedirectUri => this["yahooRedirectUrl"];
|
||||
public override string ClientID => this["yahooClientId"];
|
||||
public override string ClientSecret => this["yahooClientSecret"];
|
||||
public override string Scopes => "sdct-r";
|
||||
|
||||
public YahooLoginProvider() { }
|
||||
|
||||
public YahooLoginProvider(
|
||||
OAuth20TokenHelper oAuth20TokenHelper,
|
||||
TenantManager tenantManager,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
CoreSettings coreSettings,
|
||||
IConfiguration configuration,
|
||||
ICacheNotify<ConsumerCacheItem> cache,
|
||||
ConsumerFactory consumerFactory,
|
||||
Signature signature,
|
||||
InstanceCrypto instanceCrypto,
|
||||
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
|
||||
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional) { }
|
||||
|
||||
public OAuth20Token Auth(HttpContext context)
|
||||
{
|
||||
return Auth(context, Scopes, out var _);
|
||||
}
|
||||
|
||||
public override LoginProfile GetLoginProfile(string accessToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
@ -279,16 +279,7 @@ public class LoginProfile
|
||||
var key = HashHelper.MD5(Transport());
|
||||
memoryCache.Set(key, this, TimeSpan.FromMinutes(15));
|
||||
|
||||
return AppendQueryParam(uri, QuerySessionParamName, key);
|
||||
}
|
||||
|
||||
internal Uri AppendSessionProfile(Uri uri, HttpContext context)
|
||||
{
|
||||
//gen key
|
||||
var key = HashHelper.MD5(Transport());
|
||||
context.Session.SetString(key, JsonConvert.SerializeObject(this));
|
||||
|
||||
return AppendQueryParam(uri, QuerySessionParamName, key);
|
||||
return AppendQueryParam(uri, QueryCacheParamName, key);
|
||||
}
|
||||
|
||||
internal void ParseFromUrl(HttpContext context, Uri uri, IMemoryCache memoryCache)
|
||||
@ -298,10 +289,6 @@ public class LoginProfile
|
||||
{
|
||||
FromTransport(queryString[QueryParamName]);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(queryString[QuerySessionParamName]))
|
||||
{
|
||||
FromTransport(context.Session.GetString(queryString[QuerySessionParamName]));
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(queryString[QueryCacheParamName]))
|
||||
{
|
||||
FromTransport((string)memoryCache.Get(queryString[QueryCacheParamName]));
|
||||
|
@ -33,11 +33,6 @@ public static class LoginProfileExtensions
|
||||
return profile.AppendProfile(uri);
|
||||
}
|
||||
|
||||
public static Uri AddProfileSession(this Uri uri, LoginProfile profile, HttpContext context)
|
||||
{
|
||||
return profile.AppendSessionProfile(uri, context);
|
||||
}
|
||||
|
||||
public static Uri AddProfileCache(this Uri uri, LoginProfile profile, IMemoryCache memoryCache)
|
||||
{
|
||||
return profile.AppendCacheProfile(uri, memoryCache);
|
||||
@ -58,7 +53,7 @@ public static class LoginProfileExtensions
|
||||
}
|
||||
if (!string.IsNullOrEmpty(queryString[LoginProfile.QueryCacheParamName]))
|
||||
{
|
||||
return (LoginProfile)memoryCache.Get(queryString[LoginProfile.QuerySessionParamName]);
|
||||
return (LoginProfile)memoryCache.Get(queryString[LoginProfile.QueryCacheParamName]);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -31,7 +31,6 @@ public static class ProviderConstants
|
||||
public const string Twitter = "twitter";
|
||||
public const string Facebook = "facebook";
|
||||
public const string LinkedIn = "linkedin";
|
||||
public const string OpenId = "openid";
|
||||
public const string Box = "box";
|
||||
public const string Google = "google";
|
||||
public const string Yandex = "yandex";
|
||||
|
@ -33,6 +33,11 @@ module.exports = (app, config, logger) => {
|
||||
})
|
||||
: [];
|
||||
|
||||
if(req.originalUrl =="/isLife") {
|
||||
res.sendStatus(200);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!foundRoutes.length) {
|
||||
logger.error(`invalid route ${req.originalUrl}`);
|
||||
return res.redirect(urlResolver.getPortal404Url(req));
|
||||
|
@ -774,7 +774,7 @@ module.exports = function (app, config, logger) {
|
||||
* @desc Route to load metadata
|
||||
*/
|
||||
app.post(config.routes.loadmetadata, onLoadMetadata);
|
||||
|
||||
app.get('/isLife', (req, res) => { res.sendStatus(200); });
|
||||
/**
|
||||
* @desc Catch any untracked routes
|
||||
* @param {object} req - request with data parameter (NameID required)
|
||||
|
@ -32,6 +32,9 @@ const filenamify = require('filenamify-url');
|
||||
const webshot = require('./webshot/webshot');
|
||||
const config = require('../config');
|
||||
const log = require('./log.js');
|
||||
const fetch = require("node-fetch");
|
||||
const dns = require("dns");
|
||||
const Address = require("ipaddr.js");
|
||||
|
||||
const linkReg = /http(s)?:\/\/.*/;
|
||||
let urls = [];
|
||||
@ -46,6 +49,29 @@ const cache = new nodeCache({
|
||||
useClones: false
|
||||
});
|
||||
|
||||
function checkValidUrl(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(url)
|
||||
.then(res => {
|
||||
var host = new URL(res.url).host;
|
||||
dns.lookup(host, (err, ip, family) => {
|
||||
if (err) {
|
||||
log.error(error);
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
const address = Address.parse(ip);
|
||||
const range = address.range();
|
||||
resolve(range === 'unicast');
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
log.error(error);
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function checkFileExist(pathToFile) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.stat(pathToFile,
|
||||
@ -110,6 +136,12 @@ module.exports = function (req, res) {
|
||||
}
|
||||
|
||||
co(function* () {
|
||||
const isValidUrl = yield checkValidUrl(url);
|
||||
if (!isValidUrl) {
|
||||
res.sendFile(noThumb);
|
||||
return;
|
||||
}
|
||||
|
||||
const exists = yield checkFileExist(pathToFile);
|
||||
if (exists) {
|
||||
success();
|
||||
|
@ -14,9 +14,11 @@
|
||||
"express": "^4.17.1",
|
||||
"filenamify-url": "^2.1.2",
|
||||
"graceful-fs": "~4.2.4",
|
||||
"ipaddr.js": "^2.0.1",
|
||||
"moment": "^2.26.0",
|
||||
"nconf": "^0.11.3",
|
||||
"node-cache": "^5.1.0",
|
||||
"node-fetch": "2.6.1",
|
||||
"phantomjs-prebuilt": "^2.1.16",
|
||||
"request": "^2.88.2",
|
||||
"tmp": "~0.2.1",
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user