Is there sample c# code (not web.config) to do a Service Provide initiated call and also receiving the response from the Identity provider for HttpModule? I have a web forms application. The code below has mixed MVC stuff (which doesn't work). Thanks in advance.
var idp = Options.FromConfiguration.IdentityProviders.Default;
var defaultDestination = idp.SingleSignOnServiceUrl;
string UriString = "http://localhost:49826/sso";
Sustainsys.Saml2.WebSso.HttpRequestData request = ToHttpRequestData(context);
var result = new SignInCommand().Run(request, Options.FromConfiguration);
var httpResponseBase = new HttpResponseWrapper(context.Response);
result.ApplyCookies(httpResponseBase, false);
Related
I have a task to call the external REST API to get data from third party application.
In that, i have created a C# Console application for tried this and it is working fine and i can get the data from thirty party application via REST API.
The same code used to tried in Dynamics Custom workflow\Plugin, i have got a error below. Please give your valuable suggestion on this.
"System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel."
Note: The below options are tried but no luck.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(AlwaysGoodCertificate);
ServicePointManager.Expect100Continue = true;
Thanks,
Vasanth
It is not clear how you are calling external API from D365 Plugin.
// Call external API
static async Task<bool> CallExternalAPI(Guid beziehungId)
{
bool status = false;
HttpClient apiClient = new HttpClient();
apiClient.DefaultRequestHeaders.Accept.Clear();
apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string url = #"https://reqres.in/api/users?page=2";
HttpResponseMessage response = await apiClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
}
return status;
}
If your problem with SSL/TLS secure channel you can use WebClient.
// Could not create SSL/TLS secure channel.
// Use (SecurityProtocolType)3072
using (WebClient client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.UserAgent, "AvoidError");
ServicePointManager.Expect100Continue = true;
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
htmlCode = client.DownloadString("MY LINK");
//passing the URL again to function from which to extract the content and compare from above content.
strNewCompanyCode = client.DownloadString("MY LINK");
}
Im using ASP.Net Core 2. I need to update a user in a Azure AD with Microsofts Graph API. The API documentation states that i should send the properties of the user in the body and specify the user in the URL like so:
https://graph.windows.net/myorganization/users/{user_id}?api-version
The documentation states that it should be a PATCH request. But HTTPRequestMessage does not accept PATCH as a HttpMethod. What is the proper way to make a PATCH request with asp.net core 2?
When i google i find that all answers suggests using JsonPatch, but that is a format that is not supported by Microsoft Graph API.
This is what i have so far....
var client = new HttpClient();
var requestUri = $"{_azureAdOptions.GraphInstance}/{_azureAdOptions.GraphVersion}/{_azureAdOptions.Domain}/users/me";
var request = new HttpRequestMessage(HttpMethod., requestUri);
var accessToken = await _authenticationHelper.GetAccessTokenAsync();
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var response = await client.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
Given the nature of Http, and the craziness of developers, you can create your own http server with custom methods. The class HttpMethod was created with this in mind allowing you to specify the method as string:
var method = new HttpMethod("PATCH"); // Patch
var request = new HttpRequestMessage(method , requestUri); // Use patch
Note: The new version of HttpClient comes with Patch method by default.
I have implemented the custom security on my reporting services 2016 and it displays the login page once the URL for reporting services is typed on browser URL bar (either reports or reportserver)
I am using the following code to pass the Credentials
when i use the code WITHOUT my security extension it works and looks like this
ICredentials _executionCredentials;
CredentialCache myCache = new CredentialCache();
Uri reportServerUri = new Uri(ReportServerUrl);
myCache.Add(new Uri(reportServerUri.GetLeftPart(UriPartial.Authority)),
"NTLM", new NetworkCredential(MyUserName, MyUserPassword));
_executionCredentials = myCache;
when i use the code WITH the security extension it doesnt work and looks like this
ICredentials _executionCredentials;
CredentialCache myCache = new CredentialCache();
Uri reportServerUri = new Uri(ReportServerUrl);
myCache.Add(new Uri(reportServerUri.GetLeftPart(UriPartial.Authority)),
"Basic", new NetworkCredential(MyUserName, MyUserPassword));
_executionCredentials = myCache;
and i get an Exception saying "The response to this POST request did not contain a 'location' header. That is not supported by this client." when i actually use this credentials
Is "basic" the wrong option ?
Have anyone done this ?
Update 1
Well it turns out that my SSRS is expecting an Authorisation cookie
which i am unable to pass (according to fiddler, there is no cookie)
HttpWebRequest request;
request = (HttpWebRequest)HttpWebRequest.Create("http://mylocalcomputerwithRS/Reports_SQL2016/api/v1.0");
CookieContainer cookieJar = new CookieContainer();
request.CookieContainer = cookieJar;
Cookie authCookie = new Cookie("sqlAuthCookie", "username:password");
authCookie.Domain = ".mydomain.mylocalcomputerwithRS";
if (authCookie != null)
request.CookieContainer.Add(authCookie);
request.Timeout = -1;
HttpWebResponse myHttpWebResponse = (HttpWebResponse)request.GetResponse();
That's how I got it (SSRS 2017; api v2.0). I took the value for the "body" from Fiddler:
var handler = new HttpClientHandler();
var httpClient = new HttpClient(handler);
Assert.AreEqual(0, handler.CookieContainer.Count);
// Create a login form
var body = new Dictionary<string, string>()
{
{"__VIEWSTATE", "9cZYKBmLKR3EbLhJvaf1JI7LZ4cc0244Hpcpzt/2MsDy+ccwNaw9hswvzwepb4InPxvrgR0FJ/TpZWbLZGNEIuD/dmmqy0qXNm5/6VMn9eV+SBbdAhSupsEhmbuTTrg7sjtRig==" },
{"__VIEWSTATEGENERATOR", "480DEEB3"},
{ "__EVENTVALIDATION", "IS0IRlkvSTMCa7SfuB/lrh9f5TpFSB2wpqBZGzpoT/aKGsI5zSjooNO9QvxIh+QIvcbPFDOqTD7R0VDOH8CWkX4T4Fs29e6IL92qPik3euu5QpidxJB14t/WSqBywIMEWXy6lfVTsTWAkkMJRX8DX7OwIhSWZAEbWZUyJRSpXZK5k74jl4x85OZJ19hyfE9qwatskQ=="},
{"txtUserName", "User"},
{"txtPassword", "1"},
{"btnLogin","Войти"}
};
var content = new FormUrlEncodedContent(body);
// POST to login form
var response = await httpClient.PostAsync("http://127.0.0.1:777/ReportServer/Logon.aspx", content);
// Check the cookies created by server
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
var cookies = handler.CookieContainer.GetCookies(new Uri("http://127.0.0.1:777/ReportServer"));
Assert.AreEqual("sqlAuthCookie", cookies[0].Name);
// Make new request to secured resource
var myresponse = await httpClient.GetAsync("http://127.0.0.1:777/Reports/api/v2.0/Folders");
var stringContent = await myresponse.Content.ReadAsStringAsync();
Console.Write(stringContent);
As an alternative you can customize SSRS Custom Security Sample quite a bit.
I forked Microsoft's Custom Security Sample to do just what you are describing (needed the functionality at a client long ago and reimplemented as a shareable project on GitHub).
https://github.com/sonrai-LLC/ExtRSAuth
I created a YouTube walkthrough as well to show how one can extend and debug SSRS security with this ExtRSAuth SSRS security assembly https://www.youtube.com/watch?v=tnsWChwW7lA
TL; DR; just bypass the Microsoft example auth check in Login.aspx.cs and put your auth in Page_Load() or Page_Init() event of Login.aspx.cs- wherever you want to perform some custom logging check- and then immediately redirect auth'd user to their requested URI.
Do I need to install ASP.NET Web API Client Libraries (as this article indicates) in order to post data to a Web API server? If so, can I do so in Visual Studio 2008 from a Windows CE project?
The reasons I wonder are:
0) The client is a Windows CE project, for which I'm using Visual Studio 2008, and I don't know if ASP.NET Web API Client Libraries are available for that version; I know I don't have the NuGet Package Manager in that environment.
1) I am successfully querying data from my RESTful Web API methods without installing ASP.NET Web API Client Libraries, using code like this:
while (true)
{
deptList.departments.Clear();
string uri = String.Format("http://platypi:28642/api/Duckbills/{0}/{1}", lastIdFetched, RECORDS_TO_FETCH);
var webRequest = (HttpWebRequest) WebRequest.Create(uri);
webRequest.Method = "GET";
using (var webResponse = (HttpWebResponse)webRequest.GetResponse())
{
if (webResponse.StatusCode == HttpStatusCode.OK)
{
var reader = new StreamReader(webResponse.GetResponseStream());
string jsonizedDuckbills = reader.ReadToEnd();
List<Duckbill> duckbills = JsonConvert.DeserializeObject<List<Duckbill>>(jsonizedDuckbills);
if (duckbills.Count <= 0) break;
foreach (Duckbill duckbill in duckbills)
{
duckbillList.duckbills.Add(duckbill);
lastIdFetched = duckbill.Id;
}
} // if ((webResponse.StatusCode == HttpStatusCode.OK)
} // using HttpWebResponse
int recordsAdded = LocalDBUtils.BulkInsertDuckbills(duckbillList.duckbills);
totalRecordsAdded += recordsAdded;
} // while (true);
I'm stuck on posting, though, and the cleanest example I've seen so far for doing so is at that link already shown above.
I got an answer to my question on how to post here, but that hasn't made me smart enough yet to actually accomplish it. It's a step in the right direction, perhaps, although I reckon, based on how my client query code looks, that the client posting code would be of similar "style" (like the previously referenced article here, and unlike the likewise previously referenced answer here).
UPDATE
If I'm already providing the data in the uri string itself, as I am, like this:
string uri = String.Format("http://shannon2:28642/api/Departments/{0}/{1}", onAccountOfWally, moniker);
...why would I need to also specify it in postData? Or could I set postData (if that's just a necessary step to get the length) to those values...something like:
postData = String.Format("{0}, {1}", onAccountOfWally, moniker);
?
To talk to ASP.NET Web API, you do not necessarily need the client library, although it makes the life easier. After all, one of the benefits of HTTP services is the platform reach. Literally you can use any library that gives you HTTP capabilities. So, using WebRequest, you can do something like this. I'm using JSON in the payload. You can use XML and application/www-form-urlencoded as well. Just that you need to format the request body accordingly. Also, for complex objects, you will be better off using JSON.NET unlike formatting the JSON manually.
var request = System.Net.WebRequest.Create("http://localhost:12345/api/values");
request.Method = "POST";
string postData = "{\"firstName\":\"Steven\"," + "\"lastName\":\"Waugh\"}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/json";
request.ContentLength = byteArray.Length;
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(byteArray, 0, byteArray.Length);
}
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var reader = new System.IO.StreamReader(responseStream))
{
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
}
}
}
EDIT
If you are specifying data in URI, you do not need to specify the same in the request body. To let web API bind the parameters for you from URI, you will need to specify the route accordingly so that the placeholders are set for onAccountOfWally and moniker. Then you will need to use a simple type like string as action method parameters for web API to bind. By default, simple types are bound from URI path and query string and complex types from request body.
I am testing a product that authenticates uses using a custom STS service. The way it used to work is, when a user hits the website using the browser, we issue a redirect to hit the STS service. the STS service authenticates the user by hitting AD and then issues a SAML token with some custom claims for the user. The website then hits the STS once again to get a ActAs token so we can communicate with the data service.
And I had a automation that would mimic this behavior and its working fine in production.
We are not modifying the STS to use ADFS to authenticate instead of hitting the AD directly. So now when I hit the website, the request gets redirected to a ADFS endpoint which authenticates the user and issues a token. Then we hit the custom STS service that would use the token to authenticate the user (instead of hitting AD), add custom claims and issue a SAML token for the user. We then generate a ActAs token using this to finally hit the data service.
I am trying to update my automation for this changed behavior. So what I am doing now is hit the ADFS service, obtain a token and pass the token to the STS service so it can issue me a SAML token.
I am quite an amateur when it comes to windows identity service so i am having hard time trying to get this work. I have successfully obtained the token (Bearer Token) from the ADFS but i cant figureout how to pass this token to my custom STS so it can issue me a SAML token.
Any help would be highly appreciated. Thanks!
here is the code i am using
public static SecurityToken GetSecurityToken()
{
var endPoint = new EndpointAddress(new Uri(#"ADFS endpoint"));
var msgBinding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);
msgBinding.Security.Message.EstablishSecurityContext = false;
msgBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
var factory = new WSTrustChannelFactory(msgBinding, endPoint);
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.SupportInteractive = true;
factory.Credentials.UserName.UserName = "user";
factory.Credentials.UserName.Password = "pwd";
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
AppliesTo = new EndpointReference(#"custom STS endpoint")
};
return factory.CreateChannel().Issue(rst);
}
public static void GetUserClaimsFromSecurityTokenService(SecurityToken secToken)
{
var securityTokenManager = new SecurityTokenHandlerCollectionManager(string.Empty);
securityTokenManager[string.Empty] = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
var trustChannelFactory = new WSTrustChannelFactory(Binding, new EndpointAddress("custom STS endpoint"))
{
TrustVersion = TrustVersion.WSTrust13,
SecurityTokenHandlerCollectionManager = securityTokenManager,
};
var rst = new RequestSecurityToken(RequestTypes.Issue)
{
AppliesTo = new EndpointReference("website url"),
TokenType = SamlSecurityTokenHandler.Assertion
};
var channel = (WSTrustChannel)trustChannelFactory.CreateChannel();
channel.Open(TimeSpan.FromMinutes(15));
try
{
RequestSecurityTokenResponse rstr;
SecurityToken token = channel.Issue(rst, out rstr);
var genericToken = (GenericXmlSecurityToken)token;
var req = new SamlSecurityTokenRequirement();
var handler = new SamlSecurityTokenHandler(req)
{
Configuration = new SecurityTokenHandlerConfiguration()
};
var newToken = handler.ReadToken(new XmlNodeReader(genericToken.TokenXml));
}
finally
{
channel.Close();
}
}