Skip to content

Commit 65d1eb0

Browse files
committed
Changing UMLS/VSAC API authentication
1 parent c4a1ce9 commit 65d1eb0

22 files changed

Lines changed: 281 additions & 210 deletions

File tree

Trifolia.Config/AppSettings.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,9 @@ public static string GoogleAnalyticsGtag
3030
get { return ConfigurationManager.AppSettings["GoogleAnalyticsGtag"]; }
3131
}
3232

33-
public static string UmlsValidateUrl
33+
public static string UMLSTicketGrantingTicketURL
3434
{
35-
get { return ConfigurationManager.AppSettings["UmlsValidateUrl"]; }
36-
}
37-
38-
public static string UmlsLicenseCode
39-
{
40-
get { return ConfigurationManager.AppSettings["UmlsLicenseCode"]; }
35+
get { return ConfigurationManager.AppSettings["UMLSTicketGrantingTicketURL"]; }
4136
}
4237

4338
public static string EncryptionSecret

Trifolia.DB/Migrations/202102230058351_umls.Designer.cs

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace Trifolia.DB.Migrations
2+
{
3+
using System;
4+
using System.Data.Entity.Migrations;
5+
6+
public partial class umls : DbMigration
7+
{
8+
public override void Up()
9+
{
10+
AddColumn("dbo.user", "umlsApiKey", c => c.String(maxLength: 255));
11+
DropColumn("dbo.user", "umlsUsername");
12+
DropColumn("dbo.user", "umlsPassword");
13+
}
14+
15+
public override void Down()
16+
{
17+
AddColumn("dbo.user", "umlsPassword", c => c.String(maxLength: 255));
18+
AddColumn("dbo.user", "umlsUsername", c => c.String(maxLength: 255));
19+
DropColumn("dbo.user", "umlsApiKey");
20+
}
21+
}
22+
}

Trifolia.DB/Migrations/202102230058351_umls.resx

Lines changed: 126 additions & 0 deletions
Large diffs are not rendered by default.

Trifolia.DB/Model/user.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,9 @@ public User()
6060
[StringLength(50)]
6161
public string ExternalOrganizationType { get; set; }
6262

63-
[Column("umlsUsername")]
63+
[Column("umlsApiKey")]
6464
[StringLength(255)]
65-
public string UMLSUsername { get; set; }
66-
67-
[Column("umlsPassword")]
68-
[StringLength(255)]
69-
public string UMLSPassword { get; set; }
65+
public string UMLSApiKey { get; set; }
7066

7167
[Column("apiKey")]
7268
[StringLength(255)]

Trifolia.DB/Trifolia.DB.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@
138138
<Compile Include="Migrations\201807122126363_updateCDASchemaSeedData.Designer.cs">
139139
<DependentUpon>201807122126363_updateCDASchemaSeedData.cs</DependentUpon>
140140
</Compile>
141+
<Compile Include="Migrations\202102230058351_umls.cs" />
142+
<Compile Include="Migrations\202102230058351_umls.Designer.cs">
143+
<DependentUpon>202102230058351_umls.cs</DependentUpon>
144+
</Compile>
141145
<Compile Include="Migrations\Configuration.cs" />
142146
<Compile Include="Model\appsecurable_role.cs" />
143147
<Compile Include="Model\app_securable.cs" />
@@ -252,6 +256,9 @@
252256
<EmbeddedResource Include="Migrations\201807122126363_updateCDASchemaSeedData.resx">
253257
<DependentUpon>201807122126363_updateCDASchemaSeedData.cs</DependentUpon>
254258
</EmbeddedResource>
259+
<EmbeddedResource Include="Migrations\202102230058351_umls.resx">
260+
<DependentUpon>202102230058351_umls.cs</DependentUpon>
261+
</EmbeddedResource>
255262
</ItemGroup>
256263
<ItemGroup>
257264
<EmbeddedResource Include="Migrations\201703292147411_multipleValueSetIdentifiers.resx">

Trifolia.Import/VSAC/VSACImporter.cs

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ public VSACImporter(IObjectRepository tdb)
2626
this.tdb = tdb;
2727
}
2828

29-
public bool Authenticate(string username, string password)
29+
public bool Authenticate(string apiKey)
3030
{
31-
string tgt = UmlsHelper.Authenticate(username, password);
31+
string tgt = UmlsHelper.GetTicketGrantingTicket(apiKey);
3232
this.ticketGrantingTicket = tgt;
3333
return !string.IsNullOrEmpty(this.ticketGrantingTicket);
3434
}
@@ -41,7 +41,10 @@ public bool Authenticate(string username, string password)
4141
/// <param name="oid">The oid of the value set to retrieve. Should not include any prefix (i.e. "urn:oid:")</param>
4242
public bool ImportValueSet(string oid)
4343
{
44-
string serviceTicket = this.GetServiceTicket();
44+
string serviceTicket = UmlsHelper.GetServiceTicket(this.ticketGrantingTicket);
45+
46+
if (string.IsNullOrEmpty(serviceTicket)) return false;
47+
4548
string url = string.Format(SVS_RETRIEVE_VALUE_SET_URL_FORMAT, oid, serviceTicket);
4649
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
4750
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
@@ -58,33 +61,6 @@ public bool ImportValueSet(string oid)
5861
return false;
5962
}
6063

61-
private string GetServiceTicket()
62-
{
63-
string url = string.Format(ST_URL_FORMAT, this.ticketGrantingTicket);
64-
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
65-
byte[] rawBody = Encoding.UTF8.GetBytes("service=http://umlsks.nlm.nih.gov");
66-
webRequest.Method = "POST";
67-
webRequest.ContentType = "text/plain";
68-
webRequest.ContentLength = rawBody.Length;
69-
70-
using (var sw = webRequest.GetRequestStream())
71-
{
72-
sw.Write(rawBody, 0, rawBody.Length);
73-
}
74-
75-
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
76-
77-
if (response.StatusCode == HttpStatusCode.OK)
78-
{
79-
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
80-
{
81-
return sr.ReadToEnd();
82-
}
83-
}
84-
85-
return null;
86-
}
87-
8864
private bool ImportRetrieveValueSet(string retrieveValueSetResponse)
8965
{
9066
List<CodeSystem> codeSystems = this.tdb.CodeSystems.ToList();

Trifolia.Plugins/Validation/BaseValidator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ join vs in valueSets on vsm.ValueSetId equals vs.Id
106106

107107
try
108108
{
109-
if (!currentUser.HasValidUmlsLicense())
109+
if (!currentUser.HasValidUMLSApiKey())
110110
{
111111
results.RestrictDownload = true;
112112
results.Messages.Add("This implementation guide contains VSAC content that you do not currently have a license to. <a href=\"/Account/MyProfile\">Update your profile</a> with your UMLS/VSAC credentials to export this implementation guide.");

Trifolia.Powershell/GetVSACValueSetCommand.cs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,14 @@ public class GetVSACValueSetCommand : BaseCommand
2020

2121
[Parameter(
2222
Mandatory = true,
23-
HelpMessage = "The username to authenticate with VSAC"
23+
HelpMessage = "The API Key to authenticate with UMLS/VSAC"
2424
)]
25-
public string VSACUsername { get; set; }
26-
27-
[Parameter(
28-
Mandatory = true,
29-
HelpMessage = "The password to authenticate with VSAC"
30-
)]
31-
public string VSACPassword { get; set; }
25+
public string UMLSApiKey { get; set; }
3226

3327
protected override void ProcessRecord()
3428
{
3529
VSACImporter importer = new VSACImporter(this.tdb);
36-
importer.Authenticate(this.VSACUsername, this.VSACPassword);
30+
importer.Authenticate(this.UMLSApiKey);
3731

3832
if (importer.ImportValueSet(this.Oid))
3933
this.WriteObject("Successfully imported value set");

Trifolia.Shared/UmlsHelper.cs

Lines changed: 45 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,77 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.IO;
4-
using System.Linq;
53
using System.Net;
6-
using System.Text;
7-
using System.Threading.Tasks;
8-
using System.Xml;
94
using Trifolia.Config;
10-
using Trifolia.Logging;
115

126
namespace Trifolia.Shared
137
{
148
public class UmlsHelper
159
{
16-
private const string TGT_URL = "https://vsac.nlm.nih.gov/vsac/ws/Ticket";
17-
private const string TGT_BODY_FORMAT = "username={0}&password={1}";
18-
19-
/// <summary>
20-
/// Authenticates the user with the VSAC using the credentials specified.
21-
/// </summary>
22-
/// <param name="username">The VSAC username</param>
23-
/// <param name="password">The VSAC password</param>
24-
/// <returns>True if authenticated, otherwise false.</returns>
25-
public static string Authenticate(string username, string password)
10+
public static string GetTicketGrantingTicket(string apiKey)
2611
{
27-
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(TGT_URL);
28-
string body = string.Format(TGT_BODY_FORMAT, username, password);
29-
byte[] rawBody = Encoding.UTF8.GetBytes(body);
30-
webRequest.Method = "POST";
31-
webRequest.ContentType = "text/plain";
32-
webRequest.ContentLength = rawBody.Length;
33-
34-
using (var sw = webRequest.GetRequestStream())
35-
{
36-
sw.Write(rawBody, 0, rawBody.Length);
37-
}
12+
string url = AppSettings.UMLSTicketGrantingTicketURL;
13+
HttpWebRequest tgtRequest = (HttpWebRequest)HttpWebRequest.Create(url);
14+
tgtRequest.Method = "POST";
15+
tgtRequest.ContentType = "application/x-www-form-urlencoded";
16+
tgtRequest.Accept = "application/xml";
3817

3918
try
4019
{
41-
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
42-
43-
if (response.StatusCode == HttpStatusCode.OK)
20+
using (StreamWriter sw = new StreamWriter(tgtRequest.GetRequestStream()))
4421
{
45-
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
46-
{
47-
return sr.ReadToEnd();
48-
}
22+
sw.Write("apikey=" + apiKey);
4923
}
50-
}
51-
catch (WebException wex)
52-
{
53-
Log.For(typeof(UmlsHelper)).Error("Error authenticating with UMLS", wex);
54-
}
55-
56-
return null;
57-
}
5824

59-
public static bool ValidateCredentials(string username, string password)
60-
{
61-
string ticketGrantingTicket = Authenticate(username, password);
62-
return !string.IsNullOrEmpty(ticketGrantingTicket);
63-
}
25+
HttpWebResponse tgtResponse = (HttpWebResponse)tgtRequest.GetResponse();
6426

65-
public static bool ValidateLicense(string username, string password)
66-
{
67-
string licenseCode = AppSettings.UmlsLicenseCode;
68-
string[] query = new string[] {
69-
"user=" + Uri.EscapeDataString(username),
70-
"password=" + Uri.EscapeDataString(password),
71-
"licenseCode=" + Uri.EscapeDataString(licenseCode)
72-
};
73-
string url = AppSettings.UmlsValidateUrl + "?" + string.Join("&", query);
74-
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
75-
webRequest.Method = "POST";
76-
webRequest.ContentType = "x-www-form-urlencoded";
77-
webRequest.Accept = "application/xml";
27+
if (tgtResponse.StatusCode != HttpStatusCode.Created)
28+
return null;
7829

79-
var response = (HttpWebResponse) webRequest.GetResponse();
30+
string location = tgtResponse.GetResponseHeader("Location");
8031

81-
if (response.StatusCode != HttpStatusCode.OK)
82-
return false;
32+
if (string.IsNullOrEmpty(location) || location.IndexOf("TGT") < 0)
33+
return null;
8334

84-
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
35+
return location.Substring(location.IndexOf("TGT"));
36+
}
37+
catch
8538
{
86-
var responseContent = sr.ReadToEnd();
87-
bool isValid = false;
39+
return null;
40+
}
41+
}
8842

89-
if (responseContent.StartsWith("\"") && responseContent.EndsWith("\""))
90-
responseContent = responseContent.Substring(0, responseContent.Length - 2);
43+
public static string GetServiceTicket(string tgt)
44+
{
45+
HttpWebRequest serviceTicketRequest = (HttpWebRequest) HttpWebRequest.Create("https://utslogin.nlm.nih.gov/cas/v1/tickets/" + tgt);
46+
serviceTicketRequest.Method = "POST";
47+
serviceTicketRequest.ContentType = "application/x-www-form-urlencoded";
9148

92-
try
49+
try
50+
{
51+
using (StreamWriter sw = new StreamWriter(serviceTicketRequest.GetRequestStream()))
9352
{
94-
XmlDocument doc = new XmlDocument();
95-
doc.LoadXml(responseContent);
53+
sw.Write("service=http://umlsks.nlm.nih.gov");
54+
}
9655

97-
if (doc.DocumentElement.Name != "Result" || !Boolean.TryParse(doc.DocumentElement.InnerText, out isValid))
98-
{
99-
Log.For(typeof(UmlsHelper)).Error("Unexpected response from UMLS validation service: {0}", responseContent);
100-
return false;
101-
}
56+
HttpWebResponse stResponse = (HttpWebResponse)serviceTicketRequest.GetResponse();
10257

103-
return isValid;
104-
}
105-
catch (Exception ex)
58+
using (StreamReader sr = new StreamReader(stResponse.GetResponseStream()))
10659
{
107-
Log.For(typeof(UmlsHelper)).Error("Error validation UMLS license for {0}", ex, username);
108-
return false;
60+
return sr.ReadToEnd();
10961
}
11062
}
63+
catch
64+
{
65+
return null;
66+
}
67+
}
68+
69+
public static bool ValidateLicense(string apiKey)
70+
{
71+
string tgt = GetTicketGrantingTicket(apiKey);
72+
if (string.IsNullOrEmpty(tgt)) return false;
73+
string serviceTicket = GetServiceTicket(tgt);
74+
return !string.IsNullOrEmpty(serviceTicket);
11175
}
11276
}
11377
}

0 commit comments

Comments
 (0)