145 lines
5.8 KiB
C#
145 lines
5.8 KiB
C#
// Copyright (C) 2015, The Duplicati Team
|
|
// http://www.duplicati.com, info@duplicati.com
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as
|
|
// published by the Free Software Foundation; either version 2.1 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
using System;
|
|
using System.Net;
|
|
using Duplicati.Library.Utility;
|
|
using System.Collections.Generic;
|
|
using System.Web;
|
|
namespace Duplicati.Library
|
|
{
|
|
public class OAuthHelper : JSONWebHelper
|
|
{
|
|
private string m_token;
|
|
private string m_authid;
|
|
private DateTime m_tokenExpires = DateTime.UtcNow;
|
|
|
|
private static string _override_server = null;
|
|
|
|
public static string OAUTH_SERVER
|
|
{
|
|
get { return string.IsNullOrWhiteSpace(_override_server) ? DUPLICATI_OAUTH_SERVICE : _override_server; }
|
|
set { _override_server = value; }
|
|
}
|
|
|
|
public const string DUPLICATI_OAUTH_SERVICE = "https://duplicati-oauth-handler.appspot.com/refresh";
|
|
private const string OAUTH_LOGIN_URL_TEMPLATE = "https://duplicati-oauth-handler.appspot.com/?type={0}";
|
|
|
|
public static string OAUTH_LOGIN_URL(string modulename)
|
|
{
|
|
var u = new Library.Utility.Uri(OAUTH_SERVER);
|
|
var addr = u.SetPath("").SetQuery((u.Query ?? "") + (string.IsNullOrWhiteSpace(u.Query) ? "" : "&") + "type={0}");
|
|
return string.Format(addr.ToString(), modulename);
|
|
}
|
|
|
|
public bool AutoAuthHeader { get; set; }
|
|
|
|
public OAuthHelper(string authid, string servicename, string useragent = null)
|
|
: base(useragent)
|
|
{
|
|
m_authid = authid;
|
|
OAuthLoginUrl = OAUTH_LOGIN_URL(servicename);
|
|
|
|
if (string.IsNullOrEmpty(authid))
|
|
throw new Exception(Strings.OAuthHelper.MissingAuthID(OAuthLoginUrl));
|
|
}
|
|
|
|
public T GetTokenResponse<T>()
|
|
{
|
|
var req = CreateRequest(OAUTH_SERVER);
|
|
req.Headers["X-AuthID"] = m_authid;
|
|
req.Timeout = (int)TimeSpan.FromSeconds(25).TotalMilliseconds;
|
|
|
|
return ReadJSONResponse<T>(req);
|
|
}
|
|
|
|
public override HttpWebRequest CreateRequest(string url, string method = null)
|
|
{
|
|
var r = base.CreateRequest(url, method);
|
|
if (AutoAuthHeader && !OAUTH_SERVER.Equals(url))
|
|
r.Headers["Authorization"] = string.Format("Bearer {0}", AccessToken);
|
|
return r;
|
|
}
|
|
|
|
public string AccessToken
|
|
{
|
|
get
|
|
{
|
|
if (m_token == null || m_tokenExpires < DateTime.UtcNow)
|
|
{
|
|
var retries = 0;
|
|
|
|
while(true)
|
|
{
|
|
try
|
|
{
|
|
var res = GetTokenResponse<OAuth_Service_Response>();
|
|
|
|
m_tokenExpires = DateTime.UtcNow.AddSeconds(res.expires - 30);
|
|
return m_token = res.access_token;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var msg = ex.Message;
|
|
var clienterror = false;
|
|
if (ex is WebException)
|
|
{
|
|
var resp = ((WebException)ex).Response as HttpWebResponse;
|
|
if (resp != null)
|
|
{
|
|
msg = resp.Headers["X-Reason"];
|
|
if (string.IsNullOrWhiteSpace(msg))
|
|
msg = resp.StatusDescription;
|
|
|
|
if (resp.StatusCode == HttpStatusCode.ServiceUnavailable)
|
|
{
|
|
if (msg == resp.StatusDescription)
|
|
throw new Exception(Strings.OAuthHelper.OverQuotaError);
|
|
else
|
|
throw new Exception(Strings.OAuthHelper.AuthorizationFailure(msg, OAuthLoginUrl), ex);
|
|
}
|
|
|
|
//Fail faster on client errors
|
|
clienterror = (int)resp.StatusCode >= 400 && (int)resp.StatusCode <= 499;
|
|
}
|
|
}
|
|
|
|
if (retries >= (clienterror ? 1 : 5))
|
|
throw new Exception(Strings.OAuthHelper.AuthorizationFailure(msg, OAuthLoginUrl), ex);
|
|
|
|
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(Math.Pow(2, retries)));
|
|
retries++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return m_token;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private class OAuth_Service_Response
|
|
{
|
|
public string access_token { get; set; }
|
|
[Newtonsoft.Json.JsonProperty(NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
|
|
public int expires { get; set; }
|
|
}
|
|
|
|
}
|
|
}
|
|
|