Grails REST plugin using HTTPBuilder for HTTPS - rest

I have a service method in grails that was working fine.
It pulls a JSON via a GET request. After moving to prod we had to change the protocol to HTTPS and now I am getting an exception.
Is there anything I have to change to use the HTTPS protocol? I look all over The HTTPBuilder Documentation and I could not find a single reference to using HTTPS. I also could not find a example on Google.
def reportList = new ArrayList()
def result
//TODO Dynamic PatientKey
def http = new HTTPBuilder( 'https://mydomain/servicename?key=' + key )
reportList = null
http.request( GET, JSON ) { req ->
headers.Accept = 'application/json'
response.success = { resp, reader ->
reportList = reader.getAt("patientReports")
}
}
}
[ reportList : reportList ]

Whats the exception you are getting?
please check that SSL certificate is valid for the website. More here.
http://groovy.codehaus.org/modules/http-builder/doc/ssl.html

This Grails plugin solution works well in a test or local env because Same-Origin Policy will prevent you from implementing a front-end jQuery AJAX call since the domains are different.
In Prod, since HTTPS was used, and since the domains are the same, a jQuery AJAX call works much better then having the logic in the controller and using the REST plugin.
$.getJSON('${YOUR_URL}', function(data){ var yourData = data.yourData; //Operate on data here });

Related

Groovy Rest/HTTP Request Native for use with Script Runner

I am trying to build a simple Http Get request that requires me to submit an api key as authentication (api key as unsername and blank password). I have seen some solutions using the groovyx.net.http.HTTPBuilder library. However, the piece of code will need to be deployed in an evironment that does not allow for libraries. So I tried the following where is the url of the website i am trying to reach:
// GET
def get = new URL("<url>").openConnection();
def getRC = get.getResponseCode();
println(getRC);
if(getRC.equals(200)) {
println(get.getInputStream().getText());
}
As expected this returns error 400 since I do not include any authentication with the api key, so I tried the following where is the api key:
def get = new URL("<url>");
def authString = "<api_key>:".getBytes().encodeBase64().toString();
def conn = get.openConnection();
conn.setRequestProperty("Authorization", "Basic ${authString}");
def getRC = conn.getResponseCode();
println(getRC);
println(conn.getInputStream().getText());
But I still get the 400 error. I tried picking up the request through Fiddler but it doesn't seem to be tracking it (executing Groovy code through GroovyConsole).
The second approach works. My mistake was to not substitute spaces in the URL with % signs.

cant set Authorization Header in HttpClient ( .Net core 3.1 )

I am migrating from .net core 2.2 to 3.1. I am making an XUnit test method to test my controllers.
I successfully made and tested in .net core 2.2 projects, but after migrating to 3.1 it seems it cant set authorization header to my request so I am getting UnAuthorized from my app.
this is my Code :
[Fact]
public async void InvalidId_UnSuccessFull_GetById()
{
// Arrange
var httpClient = new HttpClient();
var token = await GetAdminAccessToken(); // Sends a login request and fetch a valid token
// httpClient.DefaultRequestHeaders.Add("Authorization",$"Bearer {token}");
httpClient.DefaultRequestHeaders.Authorization=new AuthenticationHeaderValue("Authorization",$"Bearer {token}");
var id = Guid.Empty;
// Act
var response = await httpClient.GetAsync("localhost:5000/Admin/User/{id}");
var message = await ExtractMessage(response);
// Assert
Assert.Contains(PersianErrorMessage.InvalidUserId, message);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
I debugged into httpClient class till the sendAsync method and the HttpRequestMessage request instance does not have an Authorization Header that I set above! What's wrong with my code?
The AuthenticationHeaderValue should be set like this:
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
Source: https://learn.microsoft.com/en-us/dotnet/api/system.net.http.headers.authenticationheadervalue.-ctor?view=netcore-3.1#System_Net_Http_Headers_AuthenticationHeaderValue__ctor_System_String_
There are a couple of issues that could trip you up here. This can be a frustrating issue, so hopefully, this helps. The HTTP client is more than likely sending the Authorization header. If there is any kind of redirect, the Authorization header does not travel with it. I ran into this issue once and the only problem was my original URL did not have a trailing slash at the end.
What I entered:
https://api.example.com/v3/endpoint
Server endpoint:
https://api.example.com/v3/endpoint/
Step 1, Determine if there is a redirect.
Step 2, Make your URL match the final URI exactly
Clients like curl do this automatically. In .Net 3.1, you will have to make sure your client checks for redirects. A 401 error is actually a good thing--it means you more than likely reached the right endpoint albeit without the authorization token.
You can do this in code, but just run debug and break after you get the response. Examine the RequestURI property of the RequestMessage object of the HttpResponseMessage (response.RequestMessage.RequestURI). Compare this with your initial URL. If they do not match exactly, you've been redirected and the Authorization header was lost along the way.

Using Proxy Authorization Header with ScalajHTTP

I'm getting a 407 error using scalajHTTP. I read through the repository and it seems like I should be able to pass the basic auth credentials as a base64 encoded value. I've also tried using the helper method described in the GitHub issues .proxyAuth but that is no longer part of HTTPRequest in ScalaJ according to error messages (as well as it not being in the documentation)
Any ideas? My endpoint URL is HTTPS as well as my proxy (for additional context)
val proxyHost= s"https://$forwardProxy"
val requestForward = Http(url).postData(redactedSecret)
.option(HttpOptions.allowUnsafeSSL)
.headers(("Content-Type", "application/json"), ("Proxy-Authorization", s"Basic $proxyAuth"))
.proxy(proxyHost, 8080).asString
val responseForward: HttpResponse[String] = requestForward
This issued posted in Github but still not resolved, https://github.com/scalaj/scalaj-http/issues/87
I found a solution to this problem. I researched around and after trying http client libraries, I kept getting 407 errors even though they all support proxy auth. Anyway, I ended up having to do the following.
add
import java.net.{Authenticator,PasswordAuthentication}
and the modified code body that I previously above looks like:
val requestForward: HttpRequest = Http(url).postData(data)
.header("Content-Type", "application/json")
.proxy(proxyHost, 8080)
.option(HttpOptions.allowUnsafeSSL)
Authenticator.setDefault(new Authenticator() {
override def getPasswordAuthentication(): PasswordAuthentication = {
new PasswordAuthentication( s"$username", s"$password".toCharArray())
}
})
So as you can see I removed the header from the original request object and instead overrode the credentials. Make sure you do this before you call on the response object.

Web API calls with RestSharp - prepends application/json to body causing null parameter on action

I have a Web API service that I'm trying to access via the console using RestSharp. My RestSharp code looks like this:
RestClient client = new RestClient(baseUrlString);
RestRequest request = new RestRequest("controllername/actionname");
request.RequestFormat = DataFormat.Json;
ProcessQuestion model = new ProcessQuestion()
{
Id = "123456",
InstanceId = "123",
UniqueId = "bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626",
PostedAnswer = new Dictionary<string, string>() { { "question_7907_1", "selected" }, { "question_7907_2", "selected" } }
};
request.AddBody(model);
var response = client.Execute(request)
My Web API action takes a model that has the same parameters as the above model. When the call executes, the binding fails and the parameter is null. I suspect this is due to the RestRequest.AddBody method prepending application/json to the body value as shown below:
{application/json={"Id":"123456","InstanceId":"123","UniqueId":"bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626","PostedAnswer":{"question_7907_1":"selected","question_7907_2":"selected"}}}
If I post using Fiddler the body binds to the model properly. Below is the body value I provided in Fiddler:
{'Id':'123456','InstanceId':'123','Uniqueid':'bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626','PostedAnswer':{'question_7907_1':'selected','question_7907_2':'selected'}}
Note that the body value in fiddler is the same with the exception of prepending the application/json key.
Also to note: I've tried what seems like everything...I've separated the parameters out in the action, used FromBody and FromUri attributes, tried custom DictionaryModelBinder's, tried custom ValueBinders, tried changing the way I'm using RestSharp (AddParameter with a RequestBody parameter, AddObject, different URL styles, etc.).
Has anyone else encountered this, and if so, did you solve it? I chose Web API for this service with hopes the model binding would work as it does in MVC, but I'm seeing that isn't the case.
Thanks
EDIT (resolved):
RestSharp automatically uses the JsonSerializer for objects passed in the AddBody method. I figured I was missing something simple, and indeed I was... Adding the Method.Post parameter to the RestRequest instantiation solved the problem.
Specify the method when creating the request:
RestRequest request = new RestRequest("controllername/actionname", Method.POST);
Not sure what the default serializer is for body - you can try making it explicit:
request.AddBody(request.JsonSerializer.Serialize(model));
I'm not sure where the 'application/json' is coming from - that's the Content-Type header you should be sending with your request, definitely not part of the body. So do this instead:
request.AddHeader("Content-type", "application/json; charset=utf-8");
If this doesn't help, try making your code as similar to the example on their site as possible. Try removing complexity (even if it means changing the required functionality) - get it to a point when it works and build additional functionality on that.
http://restsharp.org/

How to grab serialized in http request claims in a code using WIF?

ADFS 2.0, WIF (WS-Federation), ASP.NET: There is no http modules or any IdentityFoundation configuration defined in a web.config (like most WIF SDK samples show), instead everything is done via program code manually using WSFederationAuthenticationModule, ServiceConfiguration and SignInRequestMessage classes. I do http redirect to ADFS in a code and it seems to work fine, returning claims and redirecting user back to my web site with serialized claims in http request. So the question is how to parse this request using WIF classes, properties and methods and extract claims values from there? Thanks
Just in case want to share my experience, it might help somebody in the future. Well, solution I finally came to looks like this:
var message = SignInResponseMessage.CreateFromFormPost(Request) as SignInResponseMessage;
var rstr = new WSFederationSerializer().CreateResponse(message, new WSTrustSerializationContext(SecurityTokenHandlerCollectionManager.CreateDefaultSecurityTokenHandlerCollectionManager()));
var issuers = new ConfigurationBasedIssuerNameRegistry();
issuers.AddTrustedIssuer("630AF999EA69AF4917362D30C9EEA00C22D9A343", #"http://MyADFSServer/adfs/services/trust");
var tokenHandler = new Saml11SecurityTokenHandler {CertificateValidator = X509CertificateValidator.None};
var config = new SecurityTokenHandlerConfiguration{
CertificateValidator = X509CertificateValidator.None,
IssuerNameRegistry = issuers};
config.AudienceRestriction.AllowedAudienceUris.Add(new Uri("MyUri"));
tokenHandler.Configuration = config;
using(var reader=XmlReader.Create(new StringReader(rstr.RequestedSecurityToken.SecurityTokenXml.OuterXml)))
{
token = tokenHandler.ReadToken(reader);
}
ClaimsIdentityCollection claimsIdentity = tokenHandler.ValidateToken(token);
I found few similar code that uses SecurityTokenServiceConfiguration (it contains token handlers) instead of Saml11SecurityTokenHandler to read and parse token, however it did not work for me because of certificate validation failure. Setting SecurityTokenServiceConfiguration.CertificateValidator to X509CertificateValidator.None did not help coz Security Token Handler classes uses their own handler configuration and ignores STS configuration values, at least if you specify configuration parameters through the code like I did, however it works fine in case configuration is defined in web.config.