Api: ThirdPartyController

This commit is contained in:
pavelbannov 2020-11-11 12:11:44 +03:00
parent 4458bca039
commit 09c07e5060
16 changed files with 249 additions and 26 deletions

View File

@ -29,18 +29,29 @@ using System.Collections.Generic;
using System.Linq;
using System.Web;
using ASC.Common;
using ASC.Core.Common.Configuration;
using ASC.FederatedLogin.LoginProviders;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace ASC.FederatedLogin.Helpers
{
public static class OAuth20TokenHelper
public class OAuth20TokenHelper
{
public static void RequestCode<T>(HttpContext context, ConsumerFactory consumerFactory, string scope = null, Dictionary<string, string> additionalArgs = null) where T : Consumer, IOAuthProvider, new()
private IHttpContextAccessor HttpContextAccessor { get; }
private ConsumerFactory ConsumerFactory { get; }
public OAuth20TokenHelper(IHttpContextAccessor httpContextAccessor, ConsumerFactory consumerFactory)
{
var loginProvider = consumerFactory.Get<T>();
HttpContextAccessor = httpContextAccessor;
ConsumerFactory = consumerFactory;
}
public RedirectResult RequestCode<T>(string scope = null, Dictionary<string, string> additionalArgs = null) where T : Consumer, IOAuthProvider, new()
{
var loginProvider = ConsumerFactory.Get<T>();
var requestUrl = loginProvider.CodeUrl;
var clientID = loginProvider.ClientID;
var redirectUri = loginProvider.RedirectUri;
@ -55,7 +66,7 @@ namespace ASC.FederatedLogin.Helpers
if (!string.IsNullOrEmpty(redirectUri)) query += "&redirect_uri=" + HttpUtility.UrlEncode(redirectUri);
if (!string.IsNullOrEmpty(scope)) query += "&scope=" + HttpUtility.UrlEncode(scope);
query += "&state=" + HttpUtility.UrlEncode(context.Request.GetUrlRewriter().AbsoluteUri);
query += "&state=" + HttpUtility.UrlEncode(HttpContextAccessor.HttpContext.Request.GetUrlRewriter().AbsoluteUri) + "/code";
if (additionalArgs != null)
{
@ -66,7 +77,7 @@ namespace ASC.FederatedLogin.Helpers
+ "=" + HttpUtility.UrlEncode((additionalArgs[additionalArg] ?? "").Trim())) : null);
}
context.Response.Redirect(uriBuilder.Uri + "?" + query, true);
return new RedirectResult(uriBuilder.Uri + "?" + query);
}
public static OAuth20Token GetAccessToken<T>(ConsumerFactory consumerFactory, string authCode) where T : Consumer, IOAuthProvider, new()
@ -145,4 +156,15 @@ namespace ASC.FederatedLogin.Helpers
return !string.IsNullOrEmpty(token.ClientID) && !string.IsNullOrEmpty(token.ClientSecret);
}
}
public static class OAuth20TokenHelperExtension
{
public static DIHelper AddOAuth20TokenHelperService(this DIHelper services)
{
services.TryAddScoped<OAuth20TokenHelper>();
return services
.AddConsumerFactoryService();
}
}
}

View File

@ -40,7 +40,24 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
namespace ASC.FederatedLogin.LoginProviders
{
{
public enum LoginProviderEnum
{
Facebook,
Google,
Dropbox,
Docusign,
Box,
OneDrive,
GosUslugi,
LinkedIn,
MailRu,
VK,
Wordpress,
Yahoo,
Yandex
}
public abstract class BaseLoginProvider<T> : Consumer, ILoginProvider where T : Consumer, ILoginProvider, new()
{
public T Instance
@ -68,6 +85,7 @@ namespace ASC.FederatedLogin.LoginProviders
}
}
private OAuth20TokenHelper OAuth20TokenHelper { get; }
internal Signature Signature { get; }
internal InstanceCrypto InstanceCrypto { get; }
@ -77,6 +95,7 @@ namespace ASC.FederatedLogin.LoginProviders
}
protected BaseLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
@ -88,6 +107,7 @@ namespace ASC.FederatedLogin.LoginProviders
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, name, order, props, additional)
{
OAuth20TokenHelper = oAuth20TokenHelper;
Signature = signature;
InstanceCrypto = instanceCrypto;
}
@ -130,7 +150,7 @@ namespace ASC.FederatedLogin.LoginProviders
var code = context.Request.Query["code"];
if (string.IsNullOrEmpty(code))
{
OAuth20TokenHelper.RequestCode<T>(context, ConsumerFactory, scopes, additionalArgs);
OAuth20TokenHelper.RequestCode<T>(scopes, additionalArgs);
redirect = true;
return null;
}

View File

@ -40,7 +40,8 @@ namespace ASC.FederatedLogin.LoginProviders
{
public class DocuSignLoginProvider : Consumer, IOAuthProvider
{
public string Scopes { get { return "signature"; } }
public static string DocuSignLoginProviderScopes { get { return "signature"; } }
public string Scopes { get { return DocuSignLoginProviderScopes; } }
public string CodeUrl { get { return DocuSignHost + "/oauth/auth"; } }
public string AccessTokenUrl { get { return DocuSignHost + "/oauth/token"; } }
public string RedirectUri { get { return this["docuSignRedirectUrl"]; } }

View File

@ -54,6 +54,7 @@ namespace ASC.FederatedLogin.LoginProviders
public FacebookLoginProvider() { }
public FacebookLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
@ -63,7 +64,7 @@ namespace ASC.FederatedLogin.LoginProviders
Signature signature,
InstanceCrypto instanceCrypto,
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional) { }
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional) { }
public override LoginProfile GetLoginProfile(string accessToken)
{

View File

@ -69,7 +69,9 @@ namespace ASC.FederatedLogin.LoginProviders
public override string Scopes { get { return "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email"; } }
public GoogleLoginProvider() { }
public GoogleLoginProvider(TenantManager tenantManager,
public GoogleLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
IConfiguration configuration,
@ -78,7 +80,7 @@ namespace ASC.FederatedLogin.LoginProviders
Signature signature,
InstanceCrypto instanceCrypto,
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional) { }
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional) { }
public override LoginProfile GetLoginProfile(string accessToken)
{

View File

@ -97,6 +97,7 @@ namespace ASC.FederatedLogin.LoginProviders
}
public GosUslugiLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
@ -106,7 +107,7 @@ namespace ASC.FederatedLogin.LoginProviders
Signature signature,
InstanceCrypto instanceCrypto,
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
{
}

View File

@ -77,7 +77,9 @@ namespace ASC.FederatedLogin.LoginProviders
}
public LinkedInLoginProvider() { }
public LinkedInLoginProvider(TenantManager tenantManager,
public LinkedInLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
IConfiguration configuration,
@ -86,7 +88,7 @@ namespace ASC.FederatedLogin.LoginProviders
Signature signature,
InstanceCrypto instanceCrypto,
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional) { }
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional) { }
public override LoginProfile GetLoginProfile(string accessToken)
{

View File

@ -80,7 +80,9 @@ namespace ASC.FederatedLogin.LoginProviders
{
}
public MailRuLoginProvider(TenantManager tenantManager,
public MailRuLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
IConfiguration configuration,
@ -89,7 +91,7 @@ namespace ASC.FederatedLogin.LoginProviders
Signature signature,
InstanceCrypto instanceCrypto,
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
{
}

View File

@ -40,7 +40,8 @@ namespace ASC.FederatedLogin.LoginProviders
private const string OneDriveOauthUrl = "https://login.live.com/";
public const string OneDriveApiUrl = "https://api.onedrive.com";
public string Scopes { get { return "wl.signin wl.skydrive_update wl.offline_access"; } }
public static string OneDriveLoginProviderScopes { get { return "wl.signin wl.skydrive_update wl.offline_access"; } }
public string Scopes { get { return OneDriveLoginProviderScopes; } }
public string CodeUrl { get { return OneDriveOauthUrl + "oauth20_authorize.srf"; } }
public string AccessTokenUrl { get { return OneDriveOauthUrl + "oauth20_token.srf"; } }
public string RedirectUri { get { return this["skydriveRedirectUrl"]; } }

View File

@ -84,7 +84,9 @@ namespace ASC.FederatedLogin.LoginProviders
{
}
public VKLoginProvider(TenantManager tenantManager,
public VKLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
IConfiguration configuration,
@ -93,7 +95,7 @@ namespace ASC.FederatedLogin.LoginProviders
Signature signature,
InstanceCrypto instanceCrypto,
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
{
}

View File

@ -49,7 +49,9 @@ namespace ASC.FederatedLogin.LoginProviders
{
}
public WordpressLoginProvider(TenantManager tenantManager,
public WordpressLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
IConfiguration configuration,
@ -58,7 +60,7 @@ namespace ASC.FederatedLogin.LoginProviders
Signature signature,
InstanceCrypto instanceCrypto,
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
{
}

View File

@ -31,6 +31,7 @@ using ASC.Common.Caching;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Common.Configuration;
using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.Profile;
using ASC.Security.Cryptography;
@ -52,7 +53,9 @@ namespace ASC.FederatedLogin.LoginProviders
public override string Scopes { get { return "sdct-r"; } }
public YahooLoginProvider() { }
public YahooLoginProvider(TenantManager tenantManager,
public YahooLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
IConfiguration configuration,
@ -61,7 +64,7 @@ namespace ASC.FederatedLogin.LoginProviders
Signature signature,
InstanceCrypto instanceCrypto,
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional) { }
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional) { }
public OAuth20Token Auth(HttpContext context)
{

View File

@ -77,7 +77,9 @@ namespace ASC.FederatedLogin.LoginProviders
{
}
public YandexLoginProvider(TenantManager tenantManager,
public YandexLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
IConfiguration configuration,
@ -86,7 +88,7 @@ namespace ASC.FederatedLogin.LoginProviders
Signature signature,
InstanceCrypto instanceCrypto,
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
{
}

View File

@ -0,0 +1,153 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
using System;
using System.Collections.Generic;
using System.Threading;
using System.Web;
using ASC.Common;
using ASC.Core.Common.Configuration;
using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.LoginProviders;
using ASC.Web.Api.Models;
using ASC.Web.Api.Routing;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace ASC.Web.Api.Controllers
{
[DefaultRoute]
[ApiController]
public class ThirdPartyController : ControllerBase
{
private OAuth20TokenHelper OAuth20TokenHelper { get; }
public ThirdPartyController(OAuth20TokenHelper oAuth20TokenHelper)
{
OAuth20TokenHelper = oAuth20TokenHelper;
}
[Read("{provider}")]
public RedirectResult Get(LoginProviderEnum provider)
{
switch (provider)
{
case LoginProviderEnum.Google:
return OAuth20TokenHelper.RequestCode<GoogleLoginProvider>(
GoogleLoginProvider.GoogleScopeDrive,
new Dictionary<string, string>
{
{ "access_type", "offline" },
{ "prompt", "consent" }
});
case LoginProviderEnum.Dropbox:
return OAuth20TokenHelper.RequestCode<DropboxLoginProvider>(
additionalArgs: new Dictionary<string, string>
{
{ "force_reauthentication", "true" }
});
case LoginProviderEnum.Docusign:
return OAuth20TokenHelper.RequestCode<DocuSignLoginProvider>(DocuSignLoginProvider.DocuSignLoginProviderScopes,
new Dictionary<string, string>
{
{ "prompt", "login" }
});
case LoginProviderEnum.Box:
return OAuth20TokenHelper.RequestCode<BoxLoginProvider>();
case LoginProviderEnum.OneDrive:
return OAuth20TokenHelper.RequestCode<OneDriveLoginProvider>(OneDriveLoginProvider.OneDriveLoginProviderScopes);
case LoginProviderEnum.Wordpress:
return OAuth20TokenHelper.RequestCode<WordpressLoginProvider>();
}
return null;
}
[Read("{provider}/code")]
public object GetCode(string redirect, string code, string error)
{
try
{
if (!string.IsNullOrEmpty(error))
{
if (error == "access_denied")
{
error = "Canceled at provider";
}
throw new Exception(error);
}
if (!string.IsNullOrEmpty(redirect))
{
return AppendCode(redirect, code);
}
return code;
}
catch (ThreadAbortException)
{
}
catch (Exception ex)
{
if (!string.IsNullOrEmpty(redirect))
{
return AppendCode(redirect, error: ex.Message);
}
return ex.Message;
}
return null;
}
private static string AppendCode(string url, string code = null, string error = null)
{
url += (url.Contains("#") ? "&" : "#")
+ (string.IsNullOrEmpty(error)
? (string.IsNullOrEmpty(code)
? string.Empty
: "code=" + HttpUtility.UrlEncode(code))
: ("error/" + HttpUtility.UrlEncode(error)));
return url;
}
}
public static class ThirdPartyControllerExtension
{
public static DIHelper AddThirdPartyController(this DIHelper services)
{
return services.AddOAuth20TokenHelperService();
}
}
}

View File

@ -0,0 +1,8 @@
namespace ASC.Web.Api.Models
{
public class ThirdpartyModel
{
public string Code { get; set; }
public string Redirect { get; set; }
}
}

View File

@ -37,7 +37,8 @@ namespace ASC.Web.Api
.AddPortalController()
.AddSettingsController()
.AddSecurityController()
.AddSmtpSettingsController();
.AddSmtpSettingsController()
.AddThirdPartyController();
}
public void ConfigureContainer(ContainerBuilder builder)