SAML request signature verification c# - request

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.

Related

Get file size of an URL without download

To get the file size of an URL without download, I wrote:
public static long getFileSizeWithoutDownload(String url) {
ConnectionRequest cr = new GZConnectionRequest();
cr.setUrl(url);
cr.setPost(false);
NetworkManager.getInstance().addProgressListener((NetworkEvent evt) -> {
if (cr == evt.getConnectionRequest() && evt.getLength() > 0) {
cr.kill();
}
});
NetworkManager.getInstance().addToQueueAndWait(cr);
return cr.getContentLength();
}
It seems to work on Simulator, Android and iOS with a testing URL of my Spring Boot server.
Anyway, I consider this code as a workaround, as I couldn't find an API that directly gives me the file size without starting the download first. Starting the download and then killing it works, but maybe there may be a better way to get the same result. By the way, the condition && evt.getLength() > 0 may never be satisfied in some cases (depending on the headers received), so it would be better to read only the headers, in which "Content-Length" may be present or absent.
So, my question is if, with Codename One, there is a way to download only the response headers, without starting the download. Thank you.
Using the HTTP head request should give you the content length header that you can then use to get the size of the file without triggering a download. Your code might not follow through on the download but it does physically happen so a head request would be superior.
Unfortunately while there's a nice wrapper to head in Rest. This wrapper isn't very useful since there's no API to query response headers. That would make sense as an enhancement. You would need to derive ConnectionRequest and read the server response headers to get the content length.
Thank you Shai, your answer https://stackoverflow.com/a/62124902/1277576 led me in the right direction. cr.setHttpMethod("HEAD"); simplifies the code and prevents the download from starting:
public static long getFileSizeWithoutDownload(String url) {
ConnectionRequest cr = new GZConnectionRequest();
cr.setUrl(url);
cr.setHttpMethod("HEAD");
cr.setPost(false);
NetworkManager.getInstance().addToQueueAndWait(cr);
return cr.getContentLength();
}
However, as you wrote, I can override ConnectionRequest for a more precise control of the headers. This other method performs the same function as the previous one, but it also guarantees me that the server supports partial downloads. In fact, if the server does not support partial downloads, the information about the content length would be useless for my purposes:
/**
* Returns -2 if the server doesn't accept partial downloads, -1 if the
* content length is unknow, a value greater than 0 if the Content-Length is
* known
*
* #param url
* #return must be interpreted as a boolean value: if greater than zero than
* partial downloads are supported (the returned value is the Content-Length),
* otherwise they are not supported.
*/
public static long getFileSizeWithoutDownload(String url) {
// documentation about the headers: https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
Wrapper<Long> result = new Wrapper<>(0l);
ConnectionRequest cr = new GZConnectionRequest() {
#Override
protected void readHeaders(Object connection) throws IOException {
String acceptRanges = getHeader(connection, "Accept-Ranges");
if (acceptRanges == null || !acceptRanges.equals("bytes")) {
Log.p("The partial downloads of " + url + " are not supported.", Log.WARNING);
result.set(-2l);
} else {
String contentLength = getHeader(connection, "Content-Length");
if (contentLength != null) {
result.set(Long.parseLong(contentLength));
} else {
Log.p("The Content-Length of " + url + " is unknown.", Log.WARNING);
result.set(-1l);
}
}
}
};
cr.setUrl(url);
cr.setHttpMethod("HEAD");
cr.setPost(false);
NetworkManager.getInstance().addToQueueAndWait(cr);
return result.get();
}
The readHeaders and getHeader methods are implementation dependent. I have verified that they work as desired on Simulator, Android and iOS.
Lastly, the Wrapper class is so implemented:
/**
* Generic object wrapper, as workaround for the issue "Local variables
* referenced from a lambda expression must be final or effectively final".
*/
public class Wrapper<T> {
private T object;
public Wrapper(T obj) {
this.object = obj;
}
public T get() {
return object;
}
public void set(T obj) {
this.object = obj;
}
}
I hope this detailed answer will help those who need to read HTTP headers with Codename One.

Codename one application is not able to connect with server using https request

We have created codename one application which using https request.
I have not made any changes in code.
Earlier the request could be sent using https but now their is a problem and i am unable to connect to the server using https request but i am able to connect same https url using postman.
The connection code snippet is following please refer it
new APIHandler().PropertiesLoad();
ConnectionRequest req = new ConnectionRequest() {
protected void handleErrorResponseCode(int code, String message) {
if (code != 200) {
// do something
}
}
};
req.setUrl(properties.getProperty("https_url"));
req.setPost(true);
req.setTimeout(Constant.TIMEOUT);
req.addArgument("FirstName", fName;
req.addArgument("SecondName", sName);
req.addArgument("BirthDate", bDate);
req.addArgument("Password", pWord);
NetworkManager.getInstance().addErrorListener((e) -> e.consume());
NetworkManager.getInstance().addToQueueAndWait(req);
byte[] data = req.getResponseData();
if (data == null) {
}
result = new String(data);
} catch (Exception e) {
//get nullpointer exception because result get null
result = "";
}
return result;

Error in JavaMail when running Selenium

I'm trying to extract an email running selenium and maven but I get the following error when trying to connect:
javax.mail.MessagingException: Connect failed;
nested exception is:
java.net.UnknownHostException: pop.google.com
at com.sun.mail.pop3.POP3Store.protocolConnect
But when I run the same exact code in a different project without selenium it works, any idea what's causing this?
public class EmailService {
private static String SERVER;
private static String USER;
private static String PASSWORD;
private static final String TEXT_FROM="SMS from";
/**
* Constructor to setup imap info
* #param server email server to connect
* #param usr email address of user
* #param passwd password of user
*/
public EmailService(String server, String usr, String passwd){
SERVER = server;
USER = usr;
PASSWORD = passwd;
}
public static String receive(String type, String receiver, Date d) {
Store store = null;
Folder folder= null;
SubjectTerm subject;
RecipientStringTerm recipient = new RecipientStringTerm(Message.RecipientType.TO,USER);
try{
//Get session
Properties props = new Properties();
//props.setProperty("mail.store.protocol","imaps");
props.put("mail.pop3.host", SERVER);
props.put("mail.pop3.port", "995");
props.put("mail.pop3.starttls.enable", "true");
//Session session = Session.getInstance(props, null);
Session session = Session.getDefaultInstance(props);
//Get message store and connect
store = session.getStore("pop3s");
store.connect(SERVER,USER,PASSWORD);
//Get default folder
folder = store.getDefaultFolder();
if(folder == null) throw new Exception("No Default folder");
//Get Inbox
folder = folder.getFolder("INBOX");
if(folder == null) throw new Exception ("No Inbox");
//Open folder for read only
folder.open(Folder.READ_ONLY);
That's because there is no host named "pop.google.com". Maybe you meant "pop.gmail.com"?
It probably works on some machines because of the first common mistake described in this JavaMail FAQ entry.

Restlet GWT in a Google Gadget

I am developing a GWT app for the Google Apps marketplace. I am using AppEngine with Restlet on the server side. Client side I use the GWT edition of Restlet. This is a great combination. I have my domain objects shared between client and server and as such no need for DTO's or proxies and so on. On the client side I can simply call Restlet resources :
CustomerResourceProxy customerResource = GWT.create(CustomerResourceProxy.class);
customerResource.getClientResource().setReference("/customer");
customerResource.retrieve(new Result<Customer>() { .... }
No need to parse the underlying XML or use JSNI to interpret incoming JSON.
BUT... part of the app is a GMAIL contextual gadget, and I cannot simply use the above code because all communication between a Gadget and the server must pass through GadgetsIO makeRequest.
So... just for the gadget, I will have to make the effort of parsing the XML or using JSNI to interpret the incoming JSON.
Is it überhaupt possible to hack the Restlet GWT client to pass all communication via GadgetsIO and what would it take ? Any pointers very welcome !
K.
I managed to get Restlet resources to work within a Gadget using GWT by making some changes to the Restlet GWT edition :
In GwtClientCall I replaced the standard GWT requestbuilder by the GadgetRequestBuilder (which will IoProvider.makeRequest), like this :
public GwtClientCall(GwtHttpClientHelper helper, String method, String requestUri, boolean hasEntity) {
super(helper, method, requestUri);
Reference requestRef = new Reference(requestUri);
if (requestRef.isRelative() || requestRef.getScheme().startsWith("http")) {
this.requestBuilder = new GadgetsRequestBuilder(method, requestUri);
this.requestBuilder.setTimeoutMillis(getHelper().getSocketConnectTimeoutMs());
this.responseHeadersAdded = false;
} else {
throw new IllegalArgumentException("Only HTTP or HTTPS resource URIs are allowed here");
}
}
In the gadgetsrequestbuilder, I had to make some changes so it would pass the headers in the request :
private GadgetsRequest doSend(String requestData, final RequestCallback callback) throws RequestException {
final RequestOptions options = RequestOptions.newInstance();
options.setMethodType(methodType);
if (requestData != null && requestData.length() > 0) {
options.setPostData(requestData);
}
options.setAuthorizationType(AuthorizationType.SIGNED);
options.setContentType(ContentType.DOM);
setHeaders(options);
final GadgetsRequest gadgetsRequest = new GadgetsRequest(getTimeoutMillis(), callback);
gadgetsRequest.setPending(true);
IoProvider.get().makeRequest(getUrl(), new ResponseReceivedHandler<Object>() {
public void onResponseReceived(ResponseReceivedEvent<Object> event) {
gadgetsRequest.fireOnResponseReceived(event, callback);
}
}, options);
return gadgetsRequest;
}
the gadget container by default strips the response headers, so i manually add the MediaType.APPLICATION_JAVA_OBJECT_GWT
#Override
public Series<org.restlet.client.engine.header.Header> getResponseHeaders() {
final Series<org.restlet.client.engine.header.Header> result = super.getResponseHeaders();
if (!this.responseHeadersAdded && (getResponse() != null)) {
Header[] headers = getResponse().getHeaders();
for (int i = 0; i < headers.length; i++) {
if (headers[i] != null) {
result.add(headers[i].getName(), headers[i].getValue());
}
}
result.add(HeaderConstants.HEADER_CONTENT_TYPE, MediaType.APPLICATION_JAVA_OBJECT_GWT.toString());
this.responseHeadersAdded = true;
}
return result;
}
A lot of dialogboxes for debugging later, it works :-)

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);
}

Resources