Skip to content

Commit

Permalink
add devicecode auth flow
Browse files Browse the repository at this point in the history
  • Loading branch information
Constantin Wenz committed Jul 10, 2021
1 parent 2a47d6c commit d38bb67
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 69 deletions.
33 changes: 20 additions & 13 deletions Lantern/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,12 @@ public static HttpClient getDefaultClient(String proxy = null, bool useCookies =
var client = new HttpClient(handler);
client.BaseAddress = new Uri(baseAdress);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("UA-CPU", "AMD64");
//client.DefaultRequestHeaders.Add("UA-CPU", "AMD64");
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; Win64; x64; Trident/7.0; .NET4.0C; .NET4.0E)");
return client;

}





// https://stackoverflow.com/questions/1459006/is-there-a-c-sharp-equivalent-to-pythons-unhexlify
public static byte[] Hex2Binary(string hex)
{
Expand Down Expand Up @@ -224,25 +220,36 @@ public static String getNonce(string proxy)
}
}

public static string postToTokenEndpoint(FormUrlEncodedContent formContent, string proxy, string tenant = null)
private static string postTo(string uri, FormUrlEncodedContent formContent, string proxy)
{
string uri = "/common/oauth2/token";
if (tenant != null)
{
uri = "/" + tenant + "/oauth2/token";
}
using (var message = new HttpRequestMessage(HttpMethod.Post, uri))
using (var client = Helper.getDefaultClient(proxy, false))
{
message.Headers.Add("client-request-id", Guid.NewGuid().ToString());
message.Headers.Add("return-client-request-id", "true");
//message.Headers.Add("client-request-id", Guid.NewGuid().ToString());
//message.Headers.Add("return-client-request-id", "true");
message.Content = formContent;
var response = client.SendAsync(message).Result;
var result = response.Content.ReadAsStringAsync().Result;
return result;
}
}

public static string postToDeviceCodeEndpoint(FormUrlEncodedContent formContent, string proxy)
{
string uri = "/common/oauth2/devicecode";
return postTo(uri, formContent, proxy);
}

public static string postToTokenEndpoint(FormUrlEncodedContent formContent, string proxy, string tenant = null)
{
string uri = "/common/oauth2/token";
if (tenant != null)
{
uri = "/" + tenant + "/oauth2/token";
}
return postTo(uri, formContent, proxy);
}

public static string getNonce2(string proxy)
{
var formContent = new FormUrlEncodedContent(new[]
Expand Down
17 changes: 17 additions & 0 deletions Lantern/Models/DeviceCodeResp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Lantern.Models
{
public class DeviceCodeResp
{
public string user_code { get; set; }
public string device_code { get; set; }
public string verification_url { get; set; }
public int expires_in { get; set; }
public int interval { get; set; }
public string message { get; set; }
}

}
18 changes: 18 additions & 0 deletions Lantern/Models/ErrorResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Lantern.Models
{ public class ErrorResponse
{
public string error { get; set; }
public string error_description { get; set; }
public int[] error_codes { get; set; }
public string timestamp { get; set; }
public string trace_id { get; set; }
public string correlation_id { get; set; }
public string error_uri { get; set; }
}


}
3 changes: 3 additions & 0 deletions Lantern/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ class TokenOptions : DefaultOptions
[Option(HelpText = "Set Session Key")]
public string SessionKey { get; set; }

[Option(HelpText = "Use DeviceCode authentication", Default = false)]
public bool Devicecode{ get; set; }

[Option(HelpText = "Set DerivedKey")]
public string DerivedKey { get; set; }

Expand Down
4 changes: 2 additions & 2 deletions Lantern/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private static int RunP2PAction(P2POptions opts)
};

var JWT = Helper.signJWT(headerRaw, payload, opts.DerivedKey);
result = Tokenator.getP2PCertificate(JWT, opts.Tenant, opts.Proxy);
result = Tokenator.GetP2PCertificate(JWT, opts.Tenant, opts.Proxy);

}
else if (opts.PFXPath != null && opts.Tenant != null && opts.DeviceName != null)
Expand Down Expand Up @@ -147,7 +147,7 @@ private static int RunP2PAction(P2POptions opts)

var JWT = header + "." + payload + "." + signatureb64;

result = Tokenator.getP2PCertificate(JWT, opts.Tenant, opts.Proxy);
result = Tokenator.GetP2PCertificate(JWT, opts.Tenant, opts.Proxy);
}
else
{
Expand Down
131 changes: 77 additions & 54 deletions Lantern/Tokenator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using Lantern.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
Expand All @@ -7,9 +10,31 @@ namespace Lantern
{
class Tokenator
{


private static string requestP2PCertificate(string JWT, string tenant, string proxy)
private static string RequestForPendingAuthentication(string code, string clientID, string proxy)
{
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("code",code),
new KeyValuePair<string, string>("grant_type","urn:ietf:params:oauth:grant-type:device_code"),
new KeyValuePair<string, string>("client_id", clientID)
});

return Helper.postToTokenEndpoint(formContent, proxy);

}

private static string RequestDeviceCode(string clientid, string resourceid, string proxy)
{
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", clientid),
new KeyValuePair<string, string>("resource", resourceid)
});
return Helper.postToDeviceCodeEndpoint(formContent, proxy);
}

private static string RequestP2PCertificate(string JWT, string tenant, string proxy)
{
var formContent = new FormUrlEncodedContent(new[]
{
Expand All @@ -20,7 +45,7 @@ private static string requestP2PCertificate(string JWT, string tenant, string pr
return Helper.postToTokenEndpoint(formContent, proxy, tenant);
}

private static string authenticateWithClientIDandSecret(string clientID, string clientSecret, string tenant, string proxy, string ressourceId)
private static string AuthenticateWithClientIDandSecret(string clientID, string clientSecret, string tenant, string proxy, string ressourceId)
{
var formContent = new FormUrlEncodedContent(new[]
{
Expand All @@ -32,7 +57,7 @@ private static string authenticateWithClientIDandSecret(string clientID, string
return Helper.postToTokenEndpoint(formContent, proxy, tenant);
}

private static string authenticateWithUserNameAndPassword(string username, string password, string tenant, string proxy, string clientID, string ressourceId)
private static string AuthenticateWithUserNameAndPassword(string username, string password, string tenant, string proxy, string clientID, string ressourceId)
{
var formContent = new FormUrlEncodedContent(new[]
{
Expand All @@ -46,7 +71,7 @@ private static string authenticateWithUserNameAndPassword(string username, strin
return Helper.postToTokenEndpoint(formContent, proxy, tenant);
}

private static string authenticateWithRefreshTokenToTenant(string refreshToken, string tenant, string proxy, string clientID, string ressourceId)
private static string AuthenticateWithRefreshTokenToTenant(string refreshToken, string tenant, string proxy, string clientID, string ressourceId)
{
var formContent = new FormUrlEncodedContent(new[]
{
Expand All @@ -59,7 +84,7 @@ private static string authenticateWithRefreshTokenToTenant(string refreshToken,
return Helper.postToTokenEndpoint(formContent, proxy, tenant);
}

private static string authenticateWithRefreshToken(string refreshToken, string proxy, string clientID, string ressourceId)
private static string AuthenticateWithRefreshToken(string refreshToken, string proxy, string clientID, string ressourceId)
{
var formContent = new FormUrlEncodedContent(new[]
{
Expand All @@ -71,7 +96,7 @@ private static string authenticateWithRefreshToken(string refreshToken, string p
});
return Helper.postToTokenEndpoint(formContent, proxy);
}
private static string authenticateWithCode(string code, string proxy, string clientID, string ressourceId)
private static string AuthenticateWithCode(string code, string proxy, string clientID, string ressourceId)
{
var formContent = new FormUrlEncodedContent(new[]
{
Expand All @@ -85,19 +110,19 @@ private static string authenticateWithCode(string code, string proxy, string cli
return Helper.postToTokenEndpoint(formContent, proxy);
}

public static string getP2PCertificate(string JWT, string tenant, string proxy)
public static string GetP2PCertificate(string JWT, string tenant, string proxy)
{
string result;
result = requestP2PCertificate(JWT, tenant, proxy);
result = RequestP2PCertificate(JWT, tenant, proxy);
return result;
}

public static string getTokenFromPRTAndDerivedKey(string PRT, string DerivedKey, string Context, string Proxy, string clientID = "1b730954-1685-4b74-9bfd-dac224a7b894", string resourceID = "https://graph.windows.net")
public static string GetTokenFromPRTAndDerivedKey(string PRT, string DerivedKey, string Context, string Proxy, string clientID = "1b730954-1685-4b74-9bfd-dac224a7b894", string resourceID = "https://graph.windows.net")
{
string result = null;
string prtCookie = Helper.createPRTCookie(PRT, Context, DerivedKey, Proxy);
string code = Helper.getCodeFromPRTCookie(prtCookie, Proxy, resourceID, clientID);
result = authenticateWithCode(code, Proxy, clientID, resourceID);
result = AuthenticateWithCode(code, Proxy, clientID, resourceID);
return result;
}

Expand All @@ -113,47 +138,74 @@ public static string GetTokenFromPRTAndSessionKey(string PRT, string SessionKey,

string prtCookie = Helper.createPRTCookie(PRT, contextHex, derivedSessionKeyHex, Proxy);
string code = Helper.getCodeFromPRTCookie(prtCookie, Proxy, resourceID, clientID);
result = authenticateWithCode(code, Proxy, clientID, resourceID);
result = AuthenticateWithCode(code, Proxy, clientID, resourceID);
return result;
}

public static string GetTokenFromPRTCookie(string PRTCookie, string Proxy, string clientID = "1b730954-1685-4b74-9bfd-dac224a7b894", string resourceID = "https://graph.windows.net")
{
string result = null;
string code = Helper.getCodeFromPRTCookie(PRTCookie, Proxy, resourceID, clientID);
result = authenticateWithCode(code, Proxy, clientID, resourceID);
result = AuthenticateWithCode(code, Proxy, clientID, resourceID);
return result;
}

public static string GetTokenFromRefreshToken(string RefreshToken, string Proxy, string clientID = "1b730954-1685-4b74-9bfd-dac224a7b894", string resourceID = "https://graph.windows.net")
{
string result = null;
result = authenticateWithRefreshToken(RefreshToken, Proxy, clientID, resourceID);
result = AuthenticateWithRefreshToken(RefreshToken, Proxy, clientID, resourceID);
return result;
}

public static string GetTokenFromRefreshTokenToTenant(string RefreshToken, string Tenant, string Proxy, string clientID = "1b730954-1685-4b74-9bfd-dac224a7b894", string resourceID = "https://graph.windows.net")
{
string result = null;
result = authenticateWithRefreshTokenToTenant(RefreshToken, Tenant, Proxy, clientID, resourceID);
result = AuthenticateWithRefreshTokenToTenant(RefreshToken, Tenant, Proxy, clientID, resourceID);
return result;
}


public static string GetTokenFromUsernameAndPassword(string Username, string Password, string Tenant, string Proxy, string clientID = "1b730954-1685-4b74-9bfd-dac224a7b894", string resourceID = "https://graph.windows.net")
{
string result = null;
result = authenticateWithUserNameAndPassword(Username, Password, Tenant, Proxy, clientID, resourceID);
result = AuthenticateWithUserNameAndPassword(Username, Password, Tenant, Proxy, clientID, resourceID);
return result;
}

public static string GetTokenWithClientIDAndSecret(string ClientID, string ClientSecret, string Tenant, string Proxy, string resourceID = "https://graph.windows.net")
{
string result = null;
result = authenticateWithClientIDandSecret(ClientID, ClientSecret, Tenant, Proxy, resourceID);
result = AuthenticateWithClientIDandSecret(ClientID, ClientSecret, Tenant, Proxy, resourceID);
return result;
}

public static string GetTokenFromDeviceCode(string ClientID, string ResourceID, string Proxy)
{
string result = null;
result = RequestDeviceCode(ClientID, ResourceID, Proxy);
var InitDeviceCode = JsonConvert.DeserializeObject<DeviceCodeResp>(result);
Console.WriteLine(JToken.FromObject(InitDeviceCode).ToString(Formatting.Indented));

var SecondsToWait = InitDeviceCode.interval;
int WaitedTime = 0;
while (WaitedTime < InitDeviceCode.expires_in)
{
result = RequestForPendingAuthentication(InitDeviceCode.device_code, ClientID, Proxy);
JToken parsedesults = JToken.Parse(result);
if (parsedesults["error"] != null)
{
Console.WriteLine("[+] Response from Azure: " + parsedesults["error"]);
}else
{
return result;
}
System.Threading.Thread.Sleep(SecondsToWait * 1000);
WaitedTime += SecondsToWait;
result = null;
}
return null;
}

public static string getToken(TokenOptions opts, string clientID = null, string resourceID = null)
{
string result = null;
Expand All @@ -164,9 +216,13 @@ public static string getToken(TokenOptions opts, string clientID = null, string
resourceID = opts.ResourceID;
}

if (opts.PRT != null & opts.DerivedKey != null & opts.Context != null)
if (opts.Devicecode)
{
result = getTokenFromPRTAndDerivedKey(opts.PRT, opts.DerivedKey, opts.Context, opts.Proxy, clientID, resourceID);
result = GetTokenFromDeviceCode(clientID, resourceID, opts.Proxy);
}
else if (opts.PRT != null & opts.DerivedKey != null & opts.Context != null)
{
result = GetTokenFromPRTAndDerivedKey(opts.PRT, opts.DerivedKey, opts.Context, opts.Proxy, clientID, resourceID);
}
else if (opts.PRT != null & opts.SessionKey != null)
{
Expand Down Expand Up @@ -196,39 +252,6 @@ public static string getToken(TokenOptions opts, string clientID = null, string
return result;
}

public static string getTokenFromDe(TokenOptions opts)
{
string result = null;
if (opts.PRT != null & opts.DerivedKey != null & opts.Context != null)
{
result = getTokenFromPRTAndDerivedKey(opts.PRT, opts.DerivedKey, opts.Context, opts.Proxy, opts.ClientID, opts.ResourceID);
}
else if (opts.PRT != null & opts.SessionKey != null)
{
result = GetTokenFromPRTAndSessionKey(opts.PRT, opts.SessionKey, opts.Proxy, opts.ClientID, opts.ResourceID);
}
else if (opts.PrtCookie != null)
{
result = GetTokenFromPRTCookie(opts.PrtCookie, opts.Proxy, opts.ClientID, opts.ResourceID);
}
else if (opts.RefreshToken != null)
{
result = GetTokenFromRefreshToken(opts.RefreshToken, opts.Proxy, opts.ResourceID, opts.ClientID);
}
else if (opts.UserName != null & opts.Password != null)
{
result = GetTokenFromUsernameAndPassword(opts.UserName, opts.Password, opts.Tenant, opts.Proxy, opts.ClientID, opts.ResourceID);
}
else if (opts.Tenant != null & opts.ClientID != null & opts.ClientSecret != null)
{
result = GetTokenWithClientIDAndSecret(opts.ClientID, opts.ClientSecret, opts.Tenant, opts.Proxy, opts.ResourceID);
}
else
{
Console.WriteLine("[-] Please set the corect arguments.");
return null;
}
return result;
}

}
}

0 comments on commit d38bb67

Please sign in to comment.