How do you set a cookie for a web request in Silverlight - silverlight

I want to set a cookie value for a http POST request, caqn this be done in Silverlight?
If so which class should I use HttpWebRequest, WebCLient or something else?

I think you can define the headers with the HttpWebRequest, so it's easy just define the Cookie header with the correct value, you can find a little help here.

To set the cookie:
HtmlPage.Document.SetProperty("cookie", value);
where value is something like "mykey=abcdef;".
To read it (key in this case is "mykey":
string[] cookies = HtmlPage.Document.Cookies.Split(';');
foreach (string cookie in cookies)
{
string[] keyValuePair = cookie.Split('=');
if (keyValuePair.Length == 2 && key == keyValuePair[0].Trim())
return keyValuePair[1].Trim();
}
To delete it:
string oldCookie = HtmlPage.Document.GetProperty("cookie") as String;
DateTime expiration = DateTime.UtcNow - TimeSpan.FromDays(1);
string cookie = String.Format("{0}=;expires={1}", key, expiration.ToString("R"));
HtmlPage.Document.SetProperty("cookie", cookie);

Related

Is it possible to set a boolean-value claims in your Identity Token with Duende Identity Server 5?

I'm trying to set a custom claim with some code for Duende Identity Server 5.2.3.
The claim works / is added, but it's a string and not a boolean.
I've notied -another- claim inthe JWT that is a boolean so I'm wondering, can I do this also?
Here's the code and then the sample JWT:
public class CustomTokenService : DefaultTokenService
{
public override async Task<Token> CreateIdentityTokenAsync(TokenCreationRequest request)
{
var token = await base.CreateIdentityTokenAsync(request);
bool isThisInAGracePeriod = true; // for example ...
// This doesn't work. There's no bool overload, for the 2nd argument.
// var myClaim = new Claims("in_grace_period", isThisInAGracePeriod);
// I need to convert the bool to a string, using ToString();
var myClaim = new Claims("in_grace_period", isThisInAGracePeriod.ToString());
token.Claims.Add(myClaim);
}
}
so notice:
email_verified is a bool value
in_grace_period is a string value (because I had to ToString() it :( )
Is it possible to add my custom claim as a bool so it ends up looking like how email_verified is serialized out to the token payload?
Yes, Claim class has a constructor that accepts 3 parameters and the 3rd one is value type.
var claim = new Claim(
type: "in_grace_period",
value: isThisInAGracePeriod.ToString().ToLower(),
valueType: ClaimValueTypes.Boolean);

Azure AAD MSAL calls resulting in AADSTS50196 exception The server terminated an operation because it encountered a client request loop

We are using MSAL to get the Auth Token and giving a call to Dynamics CRM (using the username and password) and then hoping the cached token is leveraged on subsequent request. All works fine when we have 1 user accesing it but in our load test where we have 50 concurrent users hitting in a 1 minute time this raises exception:
(AADSTS50196: The server terminated an operation because it encountered a client request loop. Please contact your app vendor.
I understand and read about the throtlling of the requests here: https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Client-Throttling
But I am still not sure how and what has gone wrong with the code below that its not using the cached token and causing the app to fail, can someone help me here figure what is wrong with my code and what changes I can do to make it work? Appreciate your help
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Identity.Client;
using System;
using System.Collections.Generic;
using System.Security;
using System.Text;
namespace XXX.YYYYYYYY.Administration.Functions.PanelManagement
{
public partial class CrmService: ICrmService
{
private IMemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions {ExpirationScanFrequency = TimeSpan.FromMinutes(10)});
private Guid cacheKey = Guid.NewGuid();
public string RequestToken(string serviceUrl, string clientId, string redirectUrl, string username, string password)
{
// check if token exist in memory cache
AuthenticationResult current = null;
if (memoryCache.TryGetValue(cacheKey, out AuthenticationResult value))
current = value;
if (current != null && current.ExpiresOn < DateTimeOffset.UtcNow && current.ExtendedExpiresOn < DateTimeOffset.UtcNow)
return current.AccessToken;
//Build Microsoft.Identity.Client (MSAL) OAuth Token Request
var authBuilder = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(AadAuthorityAudience.AzureAdMultipleOrgs)
.WithRedirectUri(redirectUrl)
.Build();
var scope = serviceUrl + "//.default";
string[] scopes = { scope };
AuthenticationResult authBuilderResult;
if (username != string.Empty && password != string.Empty)
{
//Make silent Microsoft.Identity.Client (MSAL) OAuth Token Request
var securePassword = new SecureString();
foreach (char ch in password) securePassword.AppendChar(ch);
authBuilderResult = authBuilder.AcquireTokenByUsernamePassword(scopes, username, securePassword)
.ExecuteAsync().Result;
}
else
{
//Popup authentication dialog box to get token
authBuilderResult = authBuilder.AcquireTokenInteractive(scopes)
.ExecuteAsync().Result;
}
current = authBuilderResult;
// update cache, let the cache expires in 50 minutes so token can be renewed before it expires
memoryCache.Set(cacheKey, current, current.ExpiresOn.AddMinutes(-10));
//Note that an Azure AD access token has finite lifetime, default expiration is 60 minutes.
return current.AccessToken;
}
}
}
I think I found the solution and it was issue with the datetime comparison with ExpiresOn and Current time ) following is incorrect comparision:
if (current != null && current.ExpiresOn < DateTimeOffset.UtcNow && current.ExtendedExpiresOn < DateTimeOffset.UtcNow)
return current.AccessToken
Fixing this to below and re-running it causes it to pick the token from cache:
if (current != null && current.ExpiresOn > DateTimeOffset.UtcNow && current.ExtendedExpiresOn > DateTimeOffset.UtcNow)
return current.AccessToken

EpiServer - get absolute friendly url for given culture for page

I've a following setup in my Manage Websites panel
General Url is set to alloy.com
alloy.no is set for no culture
alloy.se is set for sv culture
alloy.com is set for en culture
In my code, i want to get the friendly external url for given language for given page.
So for Search page I want to get absolute friendly url in all languages.
I use following code to get friendly url for page (found on Anders G. Nordby blog):
var urlResolver = ServiceLocator.Current.GetInstance<UrlResolver>();
var pageAddress = urlResolver.GetUrl(reference, language);
var builder = new UrlBuilder(pageAddress);
Global.UrlRewriteProvider.ConvertToExternal(builder, null, Encoding.UTF8);
var friendlyUrl = builder.Uri.IsAbsoluteUri
? builder.ToString()
: UriSupport.AbsoluteUrlBySettings(builder.ToString());
return friendlyUrl;
It is simple if I will use the alloy.com webpage and in my custom code generate friendly url.
no - alloy.no/søk
se - alloy.se/sök
en - alloy.com/search
But when I use alloy.no to enter edit mode and I will try to generate address for no i get alloy.com/søk when it should be alloy.no/søk.
I found that if I use alloy.no to go to Edit Mode, code :
urlResolver.GetUrl(reference, language)
returns only /søk and code
UriSupport.AbsoluteUrlBySettings(builder.ToString())
add the General URL (alloy.com) instead of alloy.no.
How can I improve this code to take correct host name for page in different culture?
The GetUrl method of the UrlResolver will return a URL to a page that is relative or absolute depending on the current request context. A URL will be relative if the page is located in the current site and absolute if in another site or if the call is made outside a request.
If you are using EPiServer.CMS.Core version 8.0 or later there is also support for identifying one site as the primary site. This update also made it possible to explicitly request that the URL should be to the primary site by setting the ForceCanonical flag on the VirtualPathArguments parameter. If not the flag is not set, it will prefer the current site URL over the primary (given the requested content is located on the current site).
So, with this in mind, you can assume that the returned URL, if not absolute, will be relative to the currently requested site and safely combine it with the currently requested URL such as:
private static string ExternalUrl(this ContentReference contentLink, CultureInfo language)
{
var urlString = UrlResolver.Current.GetUrl(contentLink, language.Name, new VirtualPathArguments { ForceCanonical = true });
if (string.IsNullOrEmpty(urlString) || HttpContext.Current == null) return urlString;
var uri = new Uri(urlString, UriKind.RelativeOrAbsolute);
if (uri.IsAbsoluteUri) return urlString;
return new Uri(HttpContext.Current.Request.Url, uri).ToString();
}
In most cases I would probably prefer not to use HttpContext.Current directly and instead pass in the current request URL. But in this case I have opted to use it directly to keep the example more contained.
We have a support case regarding this. We want the url resolver to always return an absolute url when requesting the canonical url. This is our current solution:
public static string ExternalUrl(this PageData p, bool absoluteUrl, string languageBranch)
{
var result = ServiceLocator.Current.GetInstance<UrlResolver>().GetUrl(
p.ContentLink,
languageBranch,
new VirtualPathArguments
{
ContextMode = ContextMode.Default,
ForceCanonical = absoluteUrl
});
// HACK: Temprorary fix until GetUrl and ForceCanonical works as expected,
// i.e returning an absolute URL even if there is a HTTP context that matches the page's
// site definition and host.
if (absoluteUrl)
{
Uri relativeUri;
if (Uri.TryCreate(result, UriKind.RelativeOrAbsolute, out relativeUri))
{
if (!relativeUri.IsAbsoluteUri)
{
var siteDefinitionResolver = ServiceLocator.Current.GetInstance<SiteDefinitionResolver>();
var siteDefinition = siteDefinitionResolver.GetDefinitionForContent(p.ContentLink, true, true);
var hosts = siteDefinition.GetHosts(p.Language, true);
var host = hosts.FirstOrDefault(h => h.Type == HostDefinitionType.Primary) ?? hosts.FirstOrDefault(h => h.Type == HostDefinitionType.Undefined);
var basetUri = siteDefinition.SiteUrl;
if (host != null)
{
// Try to create a new base URI from the host with the site's URI scheme. Name should be a valid
// authority, i.e. have a port number if it differs from the URI scheme's default port number.
Uri.TryCreate(siteDefinition.SiteUrl.Scheme + "://" + host.Name, UriKind.Absolute, out basetUri);
}
var absoluteUri = new Uri(basetUri, relativeUri);
return absoluteUri.AbsoluteUri;
}
}
}
return result;
}
I also ran into this issue when writing a scheduled job running on a multilanguage, multihostname site. In order to get an absolute url with the right hostname in a HttpContext-less situation I had to combine Henrik's code with Dejan's code from here: https://www.dcaric.com/blog/episerver-how-to-get-external-page-url.
This is what I came up with:
public static string ExternalUrl(this ContentReference contentLink, CultureInfo language)
{
var urlString = UrlResolver.Current.GetUrl(contentLink, language.Name, new VirtualPathArguments { ForceCanonical = true });
var uri = new Uri(urlString, UriKind.RelativeOrAbsolute);
if (uri.IsAbsoluteUri) return urlString;
string externalUrl = HttpContext.Current == null
? UriSupport.AbsoluteUrlBySettings(urlString)
: HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + urlString;
return externalUrl;
}
I've manage to write something base on the Johan & Henry answers:
public static string GetExternalAbsoluteFriendlyUrl(
this ContentReference reference,
string language)
{
var urlResolver = ServiceLocator.Current.GetInstance<UrlResolver>();
var friendlyUrl = urlResolver.GetUrl(reference, language);
if (string.IsNullOrEmpty(friendlyUrl))
return friendlyUrl;
var uri = new Uri(friendlyUrl, UriKind.RelativeOrAbsolute);
if (uri.IsAbsoluteUri)
return friendlyUrl;
if (HttpContext.Current != null)
return new Uri(HttpContext.Current.Request.Url, uri).ToString();
var siteDefinitionResolver =
ServiceLocator.Current.GetInstance<SiteDefinitionResolver>();
var siteDefinition =
siteDefinitionResolver.GetDefinitionForContent(reference, true, true);
return new Uri(siteDefinition.SiteUrl, friendlyUrl).ToString();
}

How do I get a mixed multipart in a RESTEasy response?

I am trying to use resteasy. While I am able to do send a mixed multipart as a request to a webservice, I am unable to do get a mixed multipart in the response.
For eg: Requesting for a file (byte[] or stream) and the file name in a single Response.
Following is what I have tested:
Service code:
#Path("/myfiles")
public class MyMultiPartWebService {
#POST
#Path("/filedetail")
#Consumes("multipart/form-data")
#Produces("multipart/mixed")
public MultipartOutput fileDetail(MultipartFormDataInput input) throws IOException {
MultipartOutput multipartOutput = new MultipartOutput();
//some logic based on input to locate a file(s)
File myFile = new File("samplefile.pdf");
multipartOutput.addPart("fileName:"+ myFile.getName(), MediaType.TEXT_PLAIN_TYPE);
multipartOutput.addPart(file, MediaType.APPLICATION_OCTET_STREAM_TYPE);
return multipartOutput;
}
}
Client code:
public void getFileDetails(/*input params*/){
HttpClient client = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("urlString");
MultipartEntity multiPartEntity = new MultipartEntity();
//prepare the request details
postRequest.setEntity(multiPartEntity);
HttpResponse response = client.execute(postRequest);
HttpEntity returnEntity = response.getEntity();
//extracting data from the response
Header header = returnEntity.getContentType();
InputStream is = returnEntity.getContent();
if (is != null) {
byte[] bytes = IOUtils.toByteArray(is);
//Can we see the 2 parts that were added?
//Able to get a single InputStream only, and hence unable to differentiate two objects in the response
//Trying to see the contents - printing as string
System.out.println("Output from Response :: " + new String(bytes));
}
}
The output is as follows - able to see 2 different objects with different content types, but unable to extract them separately.
Output from Response ::
--af481055-4e4f-4860-9c0b-bb636d86d639
Content-Type: text/plain
fileName: samplefile.pdf
--af481055-4e4f-4860-9c0b-bb636d86d639
Content-Length: 1928
Content-Type: application/octet-stream
%PDF-1.4
<<pdf content printed as junk chars>>
How can I extract the 2 objects from the response?
UPDATE:
Tried the following approach to extract the different parts - use the 'boundary' to break the MultipartStream; use the content type string to extract approp object.
private void getResponeObject(HttpResponse response) throws IllegalStateException, IOException {
HttpEntity returnEntity = response.getEntity();
Header header = returnEntity.getContentType();
String boundary = header.getValue();
boundary = boundary.substring("multipart/mixed; boundary=".length(), boundary.length());
System.out.println("Boundary" + boundary); // --af481055-4e4f-4860-9c0b-bb636d86d639
InputStream is = returnEntity.getContent();
splitter(is, boundary);
}
//extract subsets from the input stream based on content type
private void splitter(InputStream is, String boundary) throws IOException {
ByteArrayOutputStream boas = null;
FileOutputStream fos = null;
MultipartStream multipartStream = new MultipartStream(is, boundary.getBytes());
boolean nextPart = multipartStream.skipPreamble();
System.out.println("NEXT PART :: " + nextPart);
while (nextPart) {
String header = multipartStream.readHeaders();
if (header.contains("Content-Type: "+MediaType.APPLICATION_OCTET_STREAM_TYPE)) {
fos = new FileOutputStream(new File("myfilename.pdf"));
multipartStream.readBodyData(fos);
} else if (header.contains("Content-Type: "+MediaType.TEXT_PLAIN_TYPE)) {
boas = new ByteArrayOutputStream();
multipartStream.readBodyData(boas);
String newString = new String( boas.toByteArray());
} else if (header.contains("Content-Type: "+ MediaType.APPLICATION_JSON_TYPE)) {
//extract string and create JSONObject from it
} else if (header.contains("Content-Type: "+MediaType.APPLICATION_XML_TYPE)) {
//extract string and create XML object from it
}
nextPart = multipartStream.readBoundary();
}
}
Is this the right approach?
UPDATE 2:
The logic above seems to work. But got another block, when receiving the RESPONSE from the webservice. I could not find any references to handle such issues in the Response.
The logic assumes that there is ONE part for a part type. If there are, say, 2 JSON parts in the response, it would be difficult to identify which part is what. In other words, though we can add the part with a key name while creating the response, we are unable to extract the key names int he client side.
Any clues?
You can try the following approach...
At the server side...
Create a wrapper object that can encapsulate all types. For eg., it could have a Map for TEXT and another Map for Binary data.
Convert the TEXT content to bytes (octet stream).
Create a MetaData which contains references to the Key names and their type. Eg., STR_MYKEY1, BYTES_MYKEY2. This metadata can also be converted into octet stream.
Add the metadata and the wrapped entity as parts to the multipart response.
At the Client side...
Read the MetaData to get the key names.
Use the key name to interpret each part. Since the Keyname from the metadata tells if the original data is a TEXT or BINARY, you should be able to extract the actual content with appropriate logic.
The same approach can be used for upstream, from client to service.
On top of this, you can compress the TEXT data which will help in reducing the content size...

Save Cookie in Silverlight Application

I have a silverlight Web Application and want to save user credentials if it checks "Keep me signed in" checkbox.
if (KeepMeSignedIn)
{
SetCookie("CECrd", userName, password);
}
The Set cookie function is as folows..
private static void SetCookie(string key, string uname, string password)
{
string cookieName = "CECrd";
string oldCookie = HtmlPage.Document.GetProperty(cookieName) as String;
DateTime expiration = DateTime.UtcNow + TimeSpan.FromDays(2000);
string cookie = String.Format("{0}={1}={2};expires={3}",key,uname, password, expiration.ToString("R"));
HtmlPage.Document.SetProperty(cookieName, cookie);
}
But i am unable to save the cookie in the browser.
Please help me out.
Cookies consist of name-value "pairs"
e.g.
Name=value
AnotherName=AnotherValue
expires=somedate
Your string.format has a property with 2 equals signs in it!
string cookie = String.Format("{0}={1}={2};expires={3}",key,uname, password, expiration.ToString("R"))
Which generates "{key}={uname}={password};expires={somedate2000daysfromnow}" which is two entries:
{key}={uname}={password}; // invalid
expires={somedate2000daysfromnow} // Valid

Resources