in this case how can I get client certificate?
thanks
Use client usb signature in web application
Hi
I have an working C# winforms app that uses a usb signature to get oAuth2 bearer token,uses Client ID(edClientID.Text),Client Secret(edSecret.Text),Callback URL(uCalback),asks for usb signature password then returns access_token and refresh_token
string code;
readonly string URL_auth = "https://site1.com/authorize";
readonly string URL_getToken = "https://site1.com/token";
readonly char lfeed = (char)13;
Token token = null;
try
{
string uCalback = HttpUtility.UrlEncode("https://www.site1.com");
string url = string.Format("{0}?response_type=code&client_id={1}&redirect_uri={2}", URL_auth, edClientID.Text, uCalback);
var handler = new WebRequestHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual
};
var cert = GetUserCertificate();
handler.ClientCertificates.Add(cert);
handler.UseProxy = false;
HttpClient client = new HttpClient(handler);
string resultString;
HttpResponseMessage result;
try
{
result = client.GetAsync(url).GetAwaiter().GetResult();
}
...
if (result.RequestMessage.RequestUri.Query.Contains("code="))
{
code = result.RequestMessage.RequestUri.Query.Replace("?code=", "");
var par = string.Format("grant_type=authorization_code&code={0}&client_id={1}&client_secret={2}&redirect_uri={3}",
code, edClientID.Text, edSecret.Text, uCalback);
try
{
result = client.PostAsync(URL_getToken, new StringContent(par)).GetAwaiter().GetResult();
resultString = result.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (resultString.Contains("access_token"))
{
var js = new JavaScriptSerializer();
token = js.Deserialize<Token>(resultString);
....
}
}
.....
}
}
}
public class Token
{
public string access_token { get; set; }
public string refresh_token { get; set; }
}
public static X509Certificate2 GetUserCertificate()
{
X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = store.Certificates;
X509Certificate2Collection fcollection = collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
X509Certificate2Collection HardCollection = new X509Certificate2Collection();
string sn = "";
foreach (var x5 in fcollection)
{
if (string.IsNullOrEmpty(sn) || (x5.SerialNumber == sn))
HardCollection.Add(x5);
}
if (HardCollection.Count > 1)
{
X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(HardCollection, "", "Select certificate", X509SelectionFlag.SingleSelection);
store.Close();
return scollection[0];
}
else
{
if (HardCollection.Count == 1)
{
store.Close();
return HardCollection[0];
}
else
{
store.Close();
return null;
}
}
}
I want to replace my winforms app with a web app(mywebapp.com),I've create a controller,but in this case,on the same computer If I go to mywebapp.com/cert/xxxxx/yyyy it doesn't ask for usb signature, If I put in browser the first GET request from the code https://site1/authorize?response_type=code&client_id=xxxxx&redirect_uri=https%3a%2f%2fwww.site1.com it asks for usb signature
[ApiController]
[Route("[controller]")]
public class CertController : ControllerBase
{
[HttpGet]
[Route("/cert/{pClientID}/{pClientSecret}")]
public IActionResult GetCert(string pClientID, string pClientSecret)
{
string code, uCalback, resultString;
const char lfeed = (char)13;
HttpResponseMessage result;
try
{
uCalback = HttpUtility.UrlEncode("https://www.site1.com");
const string URL_auth = "https://site1.com/authorize";
const string URL_getToken = "https://site1.com/token";
var cert = GetUserCertificate();
var handler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
UseProxy = false
};
handler.ClientCertificates.Add(cert);
HttpClient client = new HttpClient(handler);
try
{
result = client.GetAsync(string.Format("{0}?response_type=code&client_id={1}&redirect_uri={2}",
URL_auth, pClientID, uCalback)).GetAwaiter().GetResult();
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
if (result.RequestMessage.RequestUri.Query.Contains("code="))
{
code = result.RequestMessage.RequestUri.Query.Replace("?code=", "");
var par = string.Format("grant_type=authorization_code&code={0}&client_id={1}&client_secret={2}&redirect_uri={3}",
code, pClientID, pClientSecret, uCalback);
try
{
result = client.PostAsync(URL_getToken, new StringContent(par)).GetAwaiter().GetResult();
resultString = result.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (resultString.Contains("access_token"))
{
Token o = JsonConvert.DeserializeObject<Token>(resultString);
return Ok($"access_token={o.access_token};refresh_token={o.refresh_token}");
}
}
.....
}
}
catch (Exception ex)
{
...
}
}
thanks for any help
3 answers
Sort by: Newest
-
moris27 51 Reputation points
2022-08-11T17:03:06.777+00:00 -
Bruce Barker 801 Reputation points
2022-08-11T14:34:50.913+00:00 As the cert access code is in the controller, it run on the computer hosting the website, and will access the hosting computers certificate store.
-
moris27 51 Reputation points
2022-08-11T10:39:35.457+00:00 Hi
I've added Authorize attribute,but not workingI think web app controller reads certificates installed only on server machine(GetUserCertificate function) not on client.
thanks