ITfoxtec SAML 2.0 and ASP.NET Web Forms (ASPX) HttpRequest - itfoxtec-identity-saml2

I am trying to implement ITfoxtec SAML 2.0 in an ASP.NET Web Forms (ASPX) application.
The usual ASP.NET MVC implementation uses the statement:
binding.ReadSamlResponse(Request.ToGenericHttpRequest(), saml2AuthnResponse);
but the MVC Request is not available in Web Forms.
In VB I have tried code such as
Dim request As New ITfoxtec.Identity.Saml2.Http.HttpRequest
request.Method = "GET"
request.Query = HttpContext.Current.Request.Form
binding.ReadSamlResponse(request, saml2AuthnResponse)
but this raises the exception:
Found invalid data while decoding.
at System.IO.Compression.InflaterZlib.Inflate(FlushCode flushCode)
at System.IO.Compression.InflaterZlib.ReadInflateOutput(Byte[] outputBuffer, Int32 offset, Int32 length, FlushCode flushCode, Int32& bytesRead)
at System.IO.Compression.InflaterZlib.Inflate(Byte[] bytes, Int32 offset, Int32 length)
at System.IO.Compression.DeflateStream.Read(Byte[] array, Int32 offset, Int32 count)
at System.IO.Stream.InternalCopyTo(Stream destination, Int32 bufferSize)
at System.IO.Stream.CopyTo(Stream destination)
at ITfoxtec.Identity.Saml2.Saml2RedirectBinding.DecompressResponse(String value)
at ITfoxtec.Identity.Saml2.Saml2RedirectBinding.Read(HttpRequest request, Saml2Request saml2RequestResponse, String messageName, Boolean validateXmlSignature, Boolean detectReplayedTokens)
at ITfoxtec.Identity.Saml2.Saml2Binding`1.ReadSamlResponse(HttpRequest request, Saml2Response saml2Response)
at [my code]
How can I convert HttpContext.Current.Request to ITfoxtec.Identity.Saml2.Http.HttpRequest?
Hoping for assistance,
David.

Thank you Anders.
The issue I had occurred because I had inadvertantly declared binding as Saml2RedirectBinding instead of Saml2PostBinding. With this corrected, the ASP.NET MVC C# statement:
binding.ReadSamlResponse(Request.ToGenericHttpRequest(), saml2AuthnResponse);
needs to be as follows for ASP.NET Web Forms in VB:
Dim request As New ITfoxtec.Identity.Saml2.Http.HttpRequest With
{
.Method = HttpContext.Current.Request.HttpMethod,
.Form = HttpContext.Current.Request.Form,
.Query = New NameValueCollection,
.QueryString = ""
}
binding.ReadSamlResponse(request, saml2AuthnResponse)
in case anyone else needs this solution.
David.

You probably need to convert the HttpContext.Current.Request.QueryString into a new list.
Maybe something like this:
public static class HttpRequestExtensions
{
public static Http.HttpRequest ToGenericHttpRequest(this HttpRequest request)
{
return new Http.HttpRequest
{
Method = "GET",
QueryString = ToQueryString(HttpContext.Current.Request.RawUrl),
Query = ToNameValueCollection(HttpContext.Current.Request.QueryString)
};
}
private static string ToQueryString(string rawUrl)
{
// TODO Return the queryString....
return queryString;
}
private static NameValueCollection ToNameValueCollection(??? queryString)
{
var nv = new NameValueCollection();
foreach (var item in queryString)
{
nv.Add(item.Key, item.Value.First());
}
return nv;
}
}
Code from:
https://github.com/ITfoxtec/ITfoxtec.Identity.Saml2/blob/master/src/ITfoxtec.Identity.Saml2.MvcCore/Extensions/HttpRequestExtensions.cs

Related

SAML request signature verification c#

I am creating a SAML Identity provider, and our service provider is using a third party tool Component Space to do their end's work. Identity provider I developed takes login credentials from a user and validates that user on our active directory federation server. If the user is valid then I create an SAMLResponse, sign it with X509Certificate and post it to AssertionConsumerServiceURL which I received from SAMLRequest. Now I need to verify that the SAMLRequest is coming from a valid service provider and has not be modified in between.
Initially the service provider was using HTTP redirect binding and sending the SAMLRequest, SigAlg and Signature in query string, I tried below code to verify the signature, but it always returns false.
public bool VerifyHashDynamic(string Signature, string request)
{
bool isVerified = false;
X509Certificate2 x509 = new X509Certificate2(Server.MapPath(".") + #"\X509Certificate\SP.cer", "password");
byte[] signature = Base64DecodeArray(Signature);
byte[] signedData = Base64DecodeArray(request);
RSACryptoServiceProvider rsaCSP = (RSACryptoServiceProvider)x509.PublicKey.Key;
SHA256Managed hash = new SHA256Managed();
byte[] hashedData;
bool dataOK = rsaCSP.VerifyData(signedData, CryptoConfig.MapNameToOID("SHA256"), signature);
hashedData = hash.ComputeHash(signedData);
isVerified = rsaCSP.VerifyHash(hashedData, CryptoConfig.MapNameToOID("SHA256"), signature);
return isVerified;
}
Is there something wrong in above code, which is allowing the signature verification?
In order to make it work in another way, I asked our service provider to send AuthNRequest with embedded signature (HTTP-POST binding). For signature verification of posted AuthnRequest I tried XMLDocument verification, here is the code:
public Boolean VerifyXml()
{
string mystr = string.Empty;
mystr = "9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OnVuc3BlY2lmaWVkIiBBbGxvd0NyZWF0ZT0idHJ1ZSIgLz48L3NhbWxwOkF1dGhuUmVxdWVzdD4=";
mystr = GetXmlFromSAML(mystr, false);
mystr = mystr.TrimEnd().TrimStart();
X509Certificate2 myCert = new X509Certificate2(Server.MapPath(".") + #"\X509Certificate\SP.cer");
XmlDocument Doc = new XmlDocument();
Doc.PreserveWhitespace = false;
Doc.XmlResolver = null;
Doc.LoadXml(mystr);
// Check arguments.
if (Doc == null)
throw new ArgumentException("Doc");
// Create a new SignedXml object and pass it
// the XML document class.
SignedXml signedXml = new SignedXml(Doc);
// Find the "Signature" node and create a new
// XmlNodeList object.
XmlNodeList nodeList = Doc.GetElementsByTagName("Signature");
// Throw an exception if no signature was found.
if (nodeList.Count <= 0)
{
throw new CryptographicException("Verification failed: No Signature was found in the document.");
}
// This example only supports one signature for
// the entire XML document. Throw an exception
// if more than one signature was found.
if (nodeList.Count >= 2)
{
throw new CryptographicException("Verification failed: More that one signature was found for the document.");
}
// Load the first <signature> node.
signedXml.LoadXml((XmlElement)nodeList[0]);
// Check the signature and return the result.
return signedXml.CheckSignature(myCert, false);
}
With above verification code I get exception "SignatureDescription could not be created for the signature algorithm supplied". I am not sure how I can have this signature verification working.
Is it really possible to manually verify the SAMLRequest signature with X509Certificate? Is it fine to allow the login check without signature verification of AuthnRequest?
I have been googling all these for last one month, but had no luck. Any help is much appreciated.

How to retrieve all instances on the JHipster API for entities

When calling the generated api when using a paginator, is there any way i can call the generated REST-api to retrieve ALL instances of an object, insted of only the first 20,30,40 etc?
I find that since i am using pagination for my entity-creation and management, when i want to utilize these entities in other views (self created), then the API does not provide all the instances when calling the entity.query() in angular/js.
Is this a limitation to JHipster, or can i call the REST-API in any other way supplying info to discard the paginator?
You can modify existing rest controller for that entity. Here is an example with a Center entity.
I return all centers if there is no value for offset and limit.
#RequestMapping(value = "/centers",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<List<Center>> getAll(#RequestParam(value = "page" , required = false) Integer offset,
#RequestParam(value = "per_page", required = false) Integer limit)
throws URISyntaxException {
if(offset == null && limit == null) {
return new ResponseEntity<List<Center>>(centerRepository.findAll(), HttpStatus.OK);
} else {
Page<Center> page = centerRepository.findAll(PaginationUtil.generatePageRequest(offset, limit));
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/centers", offset, limit);
return new ResponseEntity<List<Center>>(page.getContent(), headers, HttpStatus.OK);
}
}
Then in angular, you just have to call Center.query(); without params.
It's an old question but for anyone who's looking for easy solution. You need to override default PageableHandlerMethodArgumnetResolver bean:
#Configuration
public class CustomWebConfigurer implements WebMvcConfigurer {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver();
resolver.setFallbackPageable(Pageable.unpaged());
argumentResolvers.add(resolver);
}
}

Silverlight WebClient class returning empty string

I am trying to make a basic 'Silverlight Class Library' in Silverlight 4 to return basic Facebook Information using Facebook's Graph API, but I am only getting empty strings being returned.
I am using the following code:
string _Response = "";
public string GetFacebookMe(string access_token)
{
WebClient facebookClient = new WebClient();
facebookClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(facebookClientDownloadStringCompleted);
facebookClient.DownloadStringAsync(new Uri("https://graph.facebook.com/me" + "?access_token=" + access_token));
string ret = _Response;
return ret;
}
private void facebookClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
_Response = e.Result;
}
else
{
_Response = e.Error.Message;
}
}
I tried while debugging to init _Response to the value "Default", and the string "Default" was consequently being returned. I have been messing with this for a while and I'm not sure where I'm going wrong.
Thanks in advance!
It means a lot of effort to use directly WebClient. When using Silverlight and .Net Framework 4.0 you may use Facebook C# SDK at Codeplex
Usage of the SDK is excellently covered in this blog by Prabir Shrestha

VB.NET Webbrowser System.UnauthorizedAccessException in Loop

I've had this code working for at least a year and today it threw an exception that i haven't been able to figure out why its happening. Its a Forms.WebBrowser that hits a generic site first and then a secondary site.
'first site
wbr.ScriptErrorsSuppressed = False
wbr.Navigate("http://www.bing.com/?rb=0")
Do
Application.DoEvents()
Loop Until wbr.ReadyState = WebBrowserReadyState.Complete
'second site
wbr.ScriptErrorsSuppressed = True
Dim start As DateTime = DateTime.Now
Dim loopTimeout As TimeSpan = TimeSpan.FromSeconds(timeout)
wbr.Navigate("http://www.FlightAware.com")
Do
Application.DoEvents()
'loop timer
If DateTime.Now.Subtract(start) > loopTimeout Then
'stop browser
wbr.Stop()
'throw exception
Dim eExpTme As Exception = New Exception("A loop timeout occurred in the web request.")
Throw eExpTme
End If
Loop Until wbr.ReadyState = WebBrowserReadyState.Complete
The error happens on the second site access and it shows that it errors on the very last line with
System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
at System.Windows.Forms.UnsafeNativeMethods.IHTMLLocation.GetHref()
at System.Windows.Forms.WebBrowser.get_Document()
at System.Windows.Forms.WebBrowser.get_ReadyState()
I just don't get why its errorring on the second site and not the first and what exactly that error message means. I've looked at some help forums but nothing concrete that i can use to troubleshoot.
AGP
The web site has a frame on ad.doubleclick.net, by default cross-domain frame access is disabled for the internet zone, so you get a security exception.
Catch the exception and move on. There isn't much you need to care about in the frame, doubleclick is an ad service.
You can implement IInternetSecurityManager and let IE to believe ad.doubleclick.net and FlightAware.com are the same web site, but this can cause security problem if you extend the trust to arbitrary web sites.
Here is a little hack in C# which you can convert in Vb.net:
public class CrossFrameIE
{
// Returns null in case of failure.
public static IHTMLDocument2 GetDocumentFromWindow(IHTMLWindow2 htmlWindow)
{
if (htmlWindow == null)
{
return null;
}
// First try the usual way to get the document.
try
{
IHTMLDocument2 doc = htmlWindow.document;
return doc;
}
catch (COMException comEx)
{
// I think COMException won't be ever fired but just to be sure ...
if (comEx.ErrorCode != E_ACCESSDENIED)
{
return null;
}
}
catch (System.UnauthorizedAccessException)
{
}
catch
{
// Any other error.
return null;
}
// At this point the error was E_ACCESSDENIED because the frame contains a document from another domain.
// IE tries to prevent a cross frame scripting security issue.
try
{
// Convert IHTMLWindow2 to IWebBrowser2 using IServiceProvider.
IServiceProvider sp = (IServiceProvider)htmlWindow;
// Use IServiceProvider.QueryService to get IWebBrowser2 object.
Object brws = null;
sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out brws);
// Get the document from IWebBrowser2.
IWebBrowser2 browser = (IWebBrowser2)(brws);
return (IHTMLDocument2)browser.Document;
}
catch
{
}
return null;
}
private const int E_ACCESSDENIED = unchecked((int)0x80070005L);
private static Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
private static Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E");
}
// This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface!
[ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
}

Get stream from java.sql.Blob in Hibernate

I'm trying to use hibernate #Entity with java.sql.Blob to store some binary data. Storing doesn't throw any exceptions (however, I'm not sure if it really stores the bytes), but reading does. Here is my test:
#Test
public void shouldStoreBlob() {
InputStream readFile = getClass().getResourceAsStream("myfile");
Blob blob = dao.createBlob(readFile, readFile.available());
Ent ent = new Ent();
ent.setBlob(blob);
em.persist(ent);
long id = ent.getId();
Ent fromDb = em.find(Ent.class, id);
//Exception is thrown from getBinaryStream()
byte[] fromDbBytes = IOUtils.toByteArray(fromDb.getBlob().getBinaryStream());
}
So it throws an exception:
java.sql.SQLException: could not reset reader
at org.hibernate.engine.jdbc.BlobProxy.getStream(BlobProxy.java:86)
at org.hibernate.engine.jdbc.BlobProxy.invoke(BlobProxy.java:108)
at $Proxy81.getBinaryStream(Unknown Source)
...
Why? Shouldn't it read bytes form DB here? And what can I do for it to work?
Try to refresh entity:
em.refresh(fromDb);
Stream will be reopened. I suspect that find(...) is closing the blob stream.
It is not at all clear how you are using JPA here, but certainly you do not need to deal with Blob data type directly if you are using JPA.
You just need to declare a field in the entity in question of #Lob somewhat like this:
#Lob
#Basic(fetch = LAZY)
#Column(name = "image")
private byte[] image;
Then, when you retrieve your entity, the bytes will be read back again in the field and you will be able to put them in a stream and do whatever you want with them.
Of course you will need a getter and setter methods in your entity to do the byte conversion. In the example above it would be somewhat like:
private Image getImage() {
Image result = null;
if (this.image != null && this.image.length > 0) {
result = new ImageIcon(this.image).getImage();
}
return result;
}
And the setter somewhat like this
private void setImage(Image source) {
BufferedImage buffered = new BufferedImage(source.getWidth(null), source.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffered.createGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
ImageIO.write(buffered, "JPEG", stream);
this.image = stream.toByteArray();
}
catch (IOException e) {
assert (false); // should never happen
}
}
}
You need to set a breakpoint on method org.hibernate.engine.jdbc.BlobProxy#getStream on line stream.reset() and examine a reason of IOException:
private InputStream getStream() throws SQLException {
try {
if (needsReset) {
stream.reset(); // <---- Set breakpoint here
}
}
catch ( IOException ioe) {
throw new SQLException("could not reset reader");
}
needsReset = true;
return stream;
}
In my case the reason of IOException was in usage of org.apache.commons.io.input.AutoCloseInputStream as a source for Blob:
InputStream content = new AutoCloseInputStream(stream);
...
Ent ent = new Ent();
...
Blob blob = Hibernate.getLobCreator(getSession()).createBlob(content, file.getFileSize())
ent.setBlob(blob);
em.persist(ent);
While flushing a Session hibernate closes Inpustream content (or rather org.postgresql.jdbc2.AbstractJdbc2Statement#setBlob closes Inpustream in my case). And when AutoCloseInputStream is closed - it rases an IOException in method reset()
update
In your case you use a FileInputStream - this stream also throws an exception on reset method.
There is a problem in test case. You create blob and read it from database inside one transaction. When you create Ent, Postgres jdbc driver closes InputStream while flushing a session. When you load Ent (em.find(Ent.class, id)) - you get the same BlobProxy object, that stores already closed InputStream.
Try this:
TransactionTemplate tt;
#Test
public void shouldStoreBlob() {
final long id = tt.execute(new TransactionCallback<long>()
{
#Override
public long doInTransaction(TransactionStatus status)
{
try
{
InputStream readFile = getClass().getResourceAsStream("myfile");
Blob blob = dao.createBlob(readFile, readFile.available());
Ent ent = new Ent();
ent.setBlob(blob);
em.persist(ent);
return ent.getId();
}
catch (Exception e)
{
return 0;
}
}
});
byte[] fromStorage = tt.execute(new TransactionCallback<byte[]>()
{
#Override
public byte[] doInTransaction(TransactionStatus status)
{
Ent fromDb = em.find(Ent.class, id);
try
{
return IOUtils.toByteArray(fromDb.getBlob().getBinaryStream());
}
catch (IOException e)
{
return new byte[] {};
}
}
});
}
My current and only solution is closing the write session and opening new Hibernate session to get back the streamed data. It works. However I do not know what is the difference. I called inputStream.close(), but that was not enough.
Another way:
I tried to call free() method of blob after session.save(attachment) call too, but it throws another exception:
Exception in thread "main" java.lang.AbstractMethodError: org.hibernate.lob.SerializableBlob.free()V
at my.hibernatetest.HibernateTestBLOB.storeStreamInDatabase(HibernateTestBLOB.java:142)
at my.hibernatetest.HibernateTestBLOB.main(HibernateTestBLOB.java:60)
I am using PostgreSQL 8.4 + postgresql-8.4-702.jdbc4.jar, Hibernate 3.3.1.GA
Is the method IOUtils.toByteArray closing the input stream?

Resources