I have a certificate file which I want to import into flex application to establish a secure socket connection with a sever. But I am a getting an exception which says ArgumentError: Error #2004: One of the parameters is invalid.
var urlLoader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest("xyz.crt");
urlLoader.addEventListener(Event.COMPLETE, doEvent);
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.load(request);
private function doEvent(evt:Event):void {
var ldr:URLLoader = evt.target as URLLoader;
secureSocket.addEventListener( Event.CONNECT, onConnect )
secureSocket.addEventListener( IOErrorEvent.IO_ERROR, onError );
try {
secureSocket.addBinaryChainBuildingCertificate(ldr.data,true );
secureSocket.connect( "192.168.2.100", 443 );
} catch ( error:Error ) {
Alert.show( error.toString() );
}
For me, the reason is because the certificat is encoded in PEM format.
After convert it into DER format, it works fine.
A ByteArray object containing a DER-encoded X.509 digital certificate.
Related
I am trying to implement the certificate authentication in .net core API(Server/target) and this API will be invoked in to another API(Client) .Here is the piece of code of client api which makes request to server/target api.But I'm facing an error on the server/target api .I'm running these two services from local and both certificates have already installed
Client side controller logic
[HttpGet]
public async Task<List<WeatherForecast>> Get()
{
List<WeatherForecast> weatherForecastList = new List<WeatherForecast>();
X509Certificate2 clientCert = Authentication.GetClientCertificate();
if (clientCert == null)
{
HttpActionContext actionContext = null;
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
{
ReasonPhrase = "Client Certificate Required"
};
}
HttpClientHandler requestHandler = new HttpClientHandler();
requestHandler.ClientCertificates.Add(clientCert);
requestHandler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
HttpClient client = new HttpClient(requestHandler)
{
BaseAddress = new Uri("https://localhost:11111/ServerAPI")
};
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/xml"));//ACCEPT head
using (var httpClient = new HttpClient())
{
//httpClient.DefaultRequestHeaders.Accept.Clear();
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://localhost:44386/ServerAPI"),
Method = HttpMethod.Get,
};
request.Headers.Add("X-ARR-ClientCert", clientCert.GetRawCertDataString());
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT head
//using (var response = await httpClient.GetAsync("https://localhost:11111/ServerAPI"))
using (var response = await httpClient.SendAsync(request))
{
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string apiResposne = await response.Content.ReadAsStringAsync();
weatherForecastList = JsonConvert.DeserializeObject<List<WeatherForecast>>(apiResposne);
}
}
}
return weatherForecastList;
}
authentication class
public static X509Certificate2 GetClientCertificate()
{
X509Store userCaStore = new X509Store(StoreName.TrustedPeople, StoreLocation.CurrentUser);
try
{
string str_API_Cert_Thumbprint = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
userCaStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificatesInStore = userCaStore.Certificates;
X509Certificate2Collection findResult = certificatesInStore.Find(X509FindType.FindByThumbprint, str_API_Cert_Thumbprint, false);
X509Certificate2 clientCertificate = null;
if (findResult.Count == 1)
{
clientCertificate = findResult[0];
if(System.DateTime.Today >= System.Convert.ToDateTime(clientCertificate.GetExpirationDateString()))
{
throw new Exception("Certificate has already been expired.");
}
else if (System.Convert.ToDateTime(clientCertificate.GetExpirationDateString()).AddDays(-30) <= System.DateTime.Today)
{
throw new Exception("Certificate is about to expire in 30 days.");
}
}
else
{
throw new Exception("Unable to locate the correct client certificate.");
}
return clientCertificate;
}
catch (Exception ex)
{
throw;
}
finally
{
userCaStore.Close();
}
}
Server/target api code
[HttpGet]
public IEnumerable<WeatherForecast> Getcertdata()
{
IHeaderDictionary headers = base.Request.Headers;
X509Certificate2 clientCertificate = null;
string certHeaderString = headers["X-ARR-ClientCert"];
if (!string.IsNullOrEmpty(certHeaderString))
{
//byte[] bytes = Encoding.ASCII.GetBytes(certHeaderString);
//byte[] bytes = Convert.FromBase64String(certHeaderString);
//clientCertificate = new X509Certificate2(bytes);
clientCertificate = new X509Certificate2(WebUtility.UrlDecode(certHeaderString));
var serverCertificate = new X509Certificate2(Path.Combine("abc.pfx"), "pwd");
if (clientCertificate.Thumbprint == serverCertificate.Thumbprint)
{
//Valida Cert
}
}
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray();
//return new List<WeatherForecast>();
}
You have much more problems here, the code is significantly flawed and insecure in various ways. Let's explain each issue:
HttpClient in using clause in client side controller logic
Although you expect to wrap anything that implements IDisposable in using statement. However, it is not really the case with HttpClient. Connections are not closed immediately. And with every request to client controller action, a new connection is established to remote endpoint, while previous connections sit in TIME_WAIT state. Under certain constant load, your HttpClient will exhaust TCP port pool (which is limited) and any new attempt to create a new connection will throw an exception. Here are more details on this problem: You're using HttpClient wrong and it is destabilizing your software
Microsoft recommendation is to re-use existing connections. One way to do this is to Use IHttpClientFactory to implement resilient HTTP requests. Microsoft article talks a bit about this problem:
Though this class implements IDisposable, declaring and instantiating
it within a using statement is not preferred because when the
HttpClient object gets disposed of, the underlying socket is not
immediately released, which can lead to a socket exhaustion problem.
BTW, you have created a client variable, but do not use it in any way.
Ignore certificate validation problems
The line:
requestHandler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
make you vulnerable to MITM attack.
you are doing client certificate authentication wrong
The line:
request.Headers.Add("X-ARR-ClientCert", clientCert.GetRawCertDataString());
It is not the proper way how to do client cert authentication. What you literally doing is passing certificate's public part to server. That's all. You do not prove private key possession which is required to authenticate you. The proper way to do so is:
requestHandler.ClientCertificates.Add(clientCert);
This will force client and server to perform proper client authentication and check if you possess the private key for certificate you pass (it is done in TLS handshake automatically). If you have ASP.NET on server side, then you read it this way (in controller action):
X509Certificate2 clientCert = Request.HttpContext.Connection.ClientCertificate
if (clientCert == null) {
return Unauthorized();
}
// perform client cert validation according server-side rules.
Non-standard cert store
In authentication class you open StoreName.TrustedPeople store, while normally it should be StoreName.My. TrustedPeople isn't designed to store certs with private key. It isn't a functional problem, but it is bad practice.
unnecessary try/catch clause in authentication class
If you purposely throw exceptions in method, do not use try/catch. In your case you simply rethrow exception, thus you are doing a double work. And this:
throw new Exception("Certificate is about to expire in 30 days.");
is behind me. Throwing exception on technically valid certificate? Really?
server side code
As said, all this:
IHeaderDictionary headers = base.Request.Headers;
X509Certificate2 clientCertificate = null;
string certHeaderString = headers["X-ARR-ClientCert"];
if (!string.IsNullOrEmpty(certHeaderString))
{
//byte[] bytes = Encoding.ASCII.GetBytes(certHeaderString);
//byte[] bytes = Convert.FromBase64String(certHeaderString);
//clientCertificate = new X509Certificate2(bytes);
clientCertificate = new X509Certificate2(WebUtility.UrlDecode(certHeaderString));
var serverCertificate = new X509Certificate2(Path.Combine("abc.pfx"), "pwd");
if (clientCertificate.Thumbprint == serverCertificate.Thumbprint)
{
//Valida Cert
}
}
must be replaced with:
X509Certificate2 clientCert = Request.HttpContext.Connection.ClientCertificate
if (clientCert == null) {
return Unauthorized();
}
// perform client cert validation according server-side rules.
BTW:
var serverCertificate = new X509Certificate2(Path.Combine("abc.pfx"), "pwd");
if (clientCertificate.Thumbprint == serverCertificate.Thumbprint)
{
//Valida Cert
}
This is another disaster in your code. You are loading the server certificate from PFX just to compare their thumbprints? So, you suppose that client will have a copy of server certificate? Client and server certificates must not be the same. Next thing is you are generating a lot of copies of server certificate's private key files. More private key files you generate, the slower the process is and you just generate a lot of garbage. More details on this you can find in my blog post: Handling X509KeyStorageFlags in applications
Exported Qlik Sense certificate using QMC (client.pfx, root.cer, server.pfx).
Imported certificates into IIS web server using MMC. Server and client certificates to store Personal->Certificates, root to store Trusted Root Certification Authorities.
Requested QRS API from ASP.NET controller using QlikClient certificate from store (code below). Tried various user IDs and directories, including INTERNAL/sa_repository, but in all cases got an error "An error occurred while sending the request. The client certificate credentials were not recognized".
Endpoint for test : https://server:4242/qrs/about
I've searched the web but I haven't managed to find what I'm doing wrong, what credentials I should provide.
On the other hand, as I converted exported certificates to separate .key/.crt files (using https://www.markbrilman.nl/2011/08/howto-convert-a-pfx-to-a-seperate-key-crt-file/) and used them in the Postman from web server, it worked without any problem, actually with any UserId in header (i guess it's ignored in that case).
ASP.NET controller:
public X509Certificate2 LoadQlikCertificate()
{
X509Certificate2 certificate = null;
try
{
// Open certification store (MMC)
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
// Get certiface based on the friendly name
certificate = store.Certificates.Cast<X509Certificate2>().FirstOrDefault(c => c.FriendlyName == "QlikClient");
// Logging for debugging purposes
if (certificate != null)
{
logger.Log(LogLevel.Warning, $"Certificate: {certificate.FriendlyName} {certificate.GetSerialNumberString()}");
}
else
{
logger.Log(LogLevel.Warning, $"Certificate: No certificate");
}
// Close certification store
store.Close();
// Return certificate
return certificate;
}
catch (Exception e)
{
...
}
}
/* Get Qlik API response
***********************/
[HttpGet("getqlikapi")]
public IActionResult GetQlikAPI()
{
// Get Qlik certificate
var certificate = this.LoadQlikCertificate();
try
{
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// Set server name
string server = "server";
// HARDCODED USER AND DIRECTORY FOR TESTING
string userID = "sa_repository"; // tried also other user ids
string userDirectory = "INTERNAL";
// Set Xrfkey header to prevent cross-site request forgery
string xrfkey = "abcdefg123456789";
// Create URL to REST endpoint
string url = $"https://{server}:4242/qrs/about?xrfkey={xrfkey}";
// The JSON object containing the UserId and UserDirectory
string body = $"{{ 'UserId': '{userID}', 'UserDirectory': '{userDirectory}', 'Attributes': [] }}";
// Encode the json object and get the bytes
byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
// Create the HTTP Request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
// Add the method to authentication the user
request.ClientCertificates.Add(certificate);
// POST request will be used
request.Method = "POST";
// The request will accept responses in JSON format
request.Accept = "application/json";
// A header is added to validate that this request contains a valid cross-site scripting key (the same key as the one used in the url)
request.Headers.Add("X-Qlik-Xrfkey", xrfkey);
request.ContentType = "application/json";
request.ContentLength = bodyBytes.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(bodyBytes, 0, bodyBytes.Length);
requestStream.Close();
// Make the web request and get response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
// Return string in response
//return new OkObjectResult(stream != null ? new StreamReader(stream).ReadToEnd() : string.Empty);
return new OkObjectResult("test");
}
catch (Exception e)
{
...
}
}
I ran into this issue on a system we are building.
The problem was that the user did not have rights to the certificate.
Open certificate manager (Start > Manage Computer Certificates)
Find the required certificate.
Right-click cert > All Tasks > Manage Private Keys > Add > [Select the appropriate user]
Note: Manage User Certificates does not have the Manage Private Keys option.
I am using Apache abdera to post multipart request to IBM connection 4.0 API. I am getting nullpointer exception from Abdera API. Please let me know what's the root cause.
private void createEntryWithAttachment(){
try {
String activityId = "urn:lsid:ibm.com:oa:662d0dc7-0308-48ee-8291-d730c733d2d1";
String activityIdLocal = activityId.substring(activityId.lastIndexOf(":")+1, activityId.length());
String createEntryLocal = createEntry+activityIdLocal;
Abdera abdera = new Abdera();
AbderaClient client = new AbderaClient(abdera);
AbderaClient.registerTrustManager();
System.out.println("pd --->"+pd);
client.addCookie("poktam2cl.iespc.ibm.com", "PD-S-SESSION-ID", pd, "/", null, true);
RequestOptions requestOptions = client.getDefaultRequestOptions();
requestOptions.setUseChunked(true);
requestOptions.setHeader("Connection", "close");
requestOptions.setHeader("Content-Type", "multipart/related;type=\"application/atom+xml\"");
requestOptions.setContentType("multipart/related;type=\"application/atom+xml\"");
requestOptions.setSlug("Sample.txt");
Credentials credentials = new UsernamePasswordCredentials(username, password);
client.addCredentials(createEntryLocal, AuthScope.ANY_REALM,AuthScope.ANY_SCHEME, credentials);
Entry entry = abdera.getFactory().newEntry();
entry.setTitle("create entry with attachment title ");
entry.setContent("create entry with attachment content");
javax.xml.namespace.QName field = new QName("http://www.ibm.com/xmlns/prod/sn", "field", "snx");
org.apache.abdera.model.Element fieldElement = entry.addExtension(field);
fieldElement.setAttributeValue("type", "file");
fieldElement.setAttributeValue("name", "sampletextfile1");
fieldElement.setAttributeValue("position", "3000");
FileInputStream fis = new FileInputStream(filepath);
requestOptions.setHeader("Content-Length", "35");
entry.addCategory("http://www.ibm.com/xmlns/prod/sn/type","entry", "Entry");
ClientResponse response = client.post(createEntryLocal, entry, fis, "multipart/related;type=\"application/atom+xml\"", requestOptions );
System.out.println("Entry Created with attachment's resp: " + response.getStatus());
if(response.getStatus() == 201){
System.out.println("Entry Created with attachment successfully .....");
printIBMConnectionErrorMessage(response);
}else{
System.out.println("Entry with attachment creation failed");
printIBMConnectionErrorMessage(response);
//System.exit(0);
}
} catch (Exception e) {
e.printStackTrace();
}
}
Output
java.lang.NullPointerException
at org.apache.abdera.protocol.client.util.MultipartRelatedRequestEntity.writeInput(MultipartRelatedRequestEntity.java:74)
at org.apache.abdera.protocol.client.util.MultipartRelatedRequestEntity.writeRequest(MultipartRelatedRequestEntity.java:59)
at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:499)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
at org.apache.abdera.protocol.client.AbderaClient.execute(AbderaClient.java:688)
at org.apache.abdera.protocol.client.AbderaClient.post(AbderaClient.java:306)
at JavaAgentEntryWithAttachment.createEntryWithAttachment(JavaAgentEntryWithAttachment.java:157)
at JavaAgentEntryWithAttachment.main(JavaAgentEntryWithAttachment.java:66)
This exception is coming from abdera API, class called MultipartRelatedRequestEntity.java, Line no 74. I have placed line no 74 source code below. So its clear that contentSrc is null & Abdera API not allowing me to set this value. Please let me know what I am missing here.
String contentId = entry.getContentSrc().toString();
I did in two steps:
Send the file
Call to update the data
Each with the good mime type. You can not send the file with XML mime type. And put the length of the file.
It is possible to avoid the nullpointer and do it in one request. I had the same issue and created another issue and managed to find a solution. You can find it here.
It comes down to the following code example where you create a HttpClient Part which can contain a StringPart and a FilePart
final Entry entry = // ... Create your Entry
final RequestOptions options = this.client.getDefaultRequestOptions();
options.setHeader("Content-Type", "multipart/related;type=\"application/atom+xml\"");
StringPart entryPart = new StringPart("entry", entry.toString());
entryPart.setContentType("application/atom+xml");
FilePart filePart = new FilePart("file", new File(resource.getFile()));
RequestEntity request = new MultipartRequestEntity(new Part[] { entryPart, filePart}, this.client.getHttpClientParams());
ClientResponse response = client.post(this.url + this.activityId, request, options);
Hope this will help people in the future if they are using Abdera.
I am trying to get my Flex application to authenticate with google using the instructions here:
http://code.google.com/apis/gdata/docs/as-authsub.html
I have copied the example there and am trying to get it to work. I am running my app on a loca server so I have changed the next parameter:
authSubParams['next'] = 'http://localhost/AuthSub.html';
Getting the first token works fine but when I try to get the long lived token I get an error:
getLongLivedToken: singleUseToken: 1%2Fa...
onHttpStatus: [HTTPStatusEvent type="httpStatus" bubbles=false cancelable=false eventPhase=2 status=403 responseURL=null]
onGetTokenFailed: Error #2032: Stream Error. URL: https://accounts.googleapis.com/accounts/AuthSubSessionToken
it looks like I am getting a 403 error. Any ideas?
Whole App:
<?xml version="1.0" encoding="utf-8"?>
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955"
minHeight="600"
initialize=" onInitialized() "
applicationComplete=" onLoaded() "
>
<fx:Script>
<![CDATA[
import flash.external.ExternalInterface;
import flash.net.navigateToURL;
import mx.controls.Alert;
private function onInitialized() : void {
// Load the cross domain policy file for each of the googleapis.com
// domains used. At the very least, we need the ones for the API (photos)
// and the one for AuthSub for ActionScript (accounts).
Security.loadPolicyFile('http://photos.googleapis.com/data/crossdomain.xml');
Security.loadPolicyFile('https://accounts.googleapis.com/crossdomain.xml');
}
private function onLoaded() : void {
// Once the application has loaded, check to see if an AuthSub token was
// placed into the current page's URL. If it was, the user has already
// authenticated, we can continue to connect to the the service itself.
// In a real application, the long-term cookie would also be stored and
// checked here, to remove the need for the user to authenticate for this
// application every time it is used.
var searchPortion : String = ExternalInterface.call('window.location.search.toString');
//searchPortion = "?token=tokenSavenFromPreviousAttempt";
if (searchPortion.length > 0) {
// remove the ? from the token and extract the token.
searchPortion = searchPortion.substring(1);
// NOTE: Real applications should parse the URL properly.
if (searchPortion.indexOf('token=') == 0) {
log( "token found: " + searchPortion );
getLongLivedToken(searchPortion.substring(6));
return;
}
}
// No token found; redirect the user to the AuthSub page. Note that this URL
// is on the google.com domain. We can contact the google.com domain because
// this isn't a request from within Flash, but rather a page redirect.
var getTokenPage : URLRequest = new URLRequest('https://www.google.com/accounts/AuthSubRequest');
// Construct the parameters of the AuthSub request. These are the same parameters
// as normal AuthSub, which can be found here: http://code.google.com/apis/accounts/docs/AuthSub.html#AuthSubRequest
var authSubParams : URLVariables = new URLVariables();
authSubParams['scope'] = 'http://photos.googleapis.com/data'; // photos API
authSubParams['session'] = 1; // single-use token
authSubParams['secure'] = 0; // non-secure apps
authSubParams['next'] = 'http://localhost/AuthSub.html'; // The URL of this app.
//authSubParams['next'] = 'http://localhost/'; // The URL of this app.
log( "token not found, sending AuthSubRequest" );
getTokenPage.data = authSubParams;
navigateToURL(getTokenPage, '_top');
}
private function getLongLivedToken(singleUseToken : String) : void {
// Construct a call to the AuthSub for ActionScript endpoint on accounts.googleapis.com.
// This call will exchange the single use token given to use by AuthSub for a long-term
// token that we can use to make requests to endpoints such as Photos.
var getTokenRequest : URLRequest = new URLRequest('https://accounts.googleapis.com/accounts/AuthSubSessionToken');
// Due to a bug in Flash, a URLRequest with a GET request will
// not properly send headers. We therefore use POST for this and *ALL*
// requests.
getTokenRequest.method = URLRequestMethod.POST;
// Due to a bug in Flash, a URLRequest without a valid parameter will
// not properly send headers. We therefore add a useless parameter to
// make this code work.
getTokenRequest.data = new URLVariables('pleaseignore=ignore');
// Add the AuthSub for ActionScript headers.
getTokenRequest.requestHeaders.push(new URLRequestHeader('Authorization', 'AuthSub token="' + singleUseToken + '"'));
// Create the loader to get the token itself. The loader will callback
// to the following event handlers if and when the server responds.
var getToken : URLLoader = new URLLoader();
getToken.addEventListener(Event.COMPLETE, onGetTokenResult);
getToken.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onGetTokenFailed);
getToken.addEventListener(IOErrorEvent.IO_ERROR, onGetTokenFailed);
getToken.addEventListener( HTTPStatusEvent.HTTP_STATUS, onHttpStatus );
log( "getLongLivedToken: singleUseToken: " + singleUseToken );
try {
getToken.load(getTokenRequest);
} catch (e : Error) {
log( "error:\n" + e.message );
Alert.show('Some error occurred: ' + e);
}
}
private function onGetTokenResult(e : Event) : void {
// Load the parameters from the response.
var getToken : URLLoader = URLLoader(e.target);
var params : URLVariables = new URLVariables(getToken.data);
// Parse the session token from the result. Real applications
// might at this point store the token in a long-term cookie so
// that repeated usages of the application do not require this entire
// authentication process.
var sessionToken : String = params.Token;
log( "onGetTokenResult: sessionToken: " + sessionToken );
// Trim the newline from the end of the session token.
sessionToken = sessionToken.substring(0, sessionToken.length - 1);
Alert.show('session token: [' + sessionToken + ']');
// Prepare a request to the photos API for the private album
// of the user.
var albumRequest : URLRequest = new URLRequest('http://photos.googleapis.com/data/feed/api/user/default');
albumRequest.data = new URLVariables('access=private&v=2&err=xml');
// Due to a bug in Flash, a URLRequest with a GET request will
// not properly send headers. We therefore use POST for this and *ALL*
// requests.
albumRequest.method = URLRequestMethod.POST;
var authsubHeader : String = 'AuthSub token="' + sessionToken + '"';
// Add the Authorization header which uses the session token.
albumRequest.requestHeaders.push(new URLRequestHeader('Authorization', authsubHeader));
// The X-HTTP-Method-Override header tells the Photos API to treat this request
// as a GET request, even though it is being conducted as a POST (due to the bug
// mentioned above). This is very important, as GData APIs will react differently
// to different HTTP request types.
albumRequest.requestHeaders.push(new URLRequestHeader('X-HTTP-Method-Override', 'GET'));
// We expect ATOM XML to be returned.
albumRequest.requestHeaders.push(new URLRequestHeader('Content-Type', 'application/atom+xml'));
var getAlbum : URLLoader = new URLLoader();
getAlbum.addEventListener(Event.COMPLETE, onGetAlbumResult);
getAlbum.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onGetAlbumFailed);
getAlbum.addEventListener(IOErrorEvent.IO_ERROR, onGetAlbumFailed);
try {
getAlbum.load(albumRequest);
} catch (e : Error) {
Alert.show('Some error occurred: ' + e);
}
}
private function onGetAlbumResult(e : Event) : void {
// Load the XML from the response.
var getAlbum : URLLoader = URLLoader(e.target);
Alert.show('Returned XML: ' + getAlbum.data);
}
private function onGetTokenFailed(e : ErrorEvent) : void {
log( "onGetTokenFailed: " + e.text );
Alert.show('Some error occurred: ' + e);
}
private function onGetAlbumFailed(e : ErrorEvent) : void {
log( "onGetAlbumFailed: " + e.text );
Alert.show('Some error occurred: ' + e);
}
private function onHttpStatus(e : HTTPStatusEvent) : void {
log( "onHttpStatus: " + e );
Alert.show('Some error occurred: ' + e);
}
private function log( message : String ) : void
{
trace( message );
debugOutput.text = debugOutput.text ? debugOutput.text : "";
debugOutput.text = debugOutput.text.length == 0 ? message : debugOutput.text + "\n" + message;
}
]]>
</fx:Script>
<s:TextArea
id="debugOutput"
left="5"
right="5"
top="5"
bottom="5"
/>
</s:Application>
Change:
var searchPortion : String = ExternalInterface.call('window.location.search.toString');
to
var searchPortion : String = decodeURIComponent( ExternalInterface.call('window.location.search.toString'));
private function onLoaded() : void {
// Once the application has loaded, check to see if an AuthSub token was
// placed into the current page's URL. If it was, the user has already
// authenticated, we can continue to connect to the the service itself.
// In a real application, the long-term cookie would also be stored and
// checked here, to remove the need for the user to authenticate for this
// application every time it is used.
var searchPortion : String = ExternalInterface.call('window.location.search.toString');
//searchPortion = "?token=tokenSavenFromPreviousAttempt";
if (searchPortion.length > 0) {
// remove the ? from the token and extract the token.
searchPortion = searchPortion.substring(1);
// NOTE: Real applications should parse the URL properly.
if (searchPortion.indexOf('token=') == 0) {
log( "token found: " + searchPortion );
getLongLivedToken(searchPortion.substring(6));
return;
}
}
token is not properly parsed. Use
var token:String = Application.application.parameters["token"];
instead;
I'm trying to communicate my flash application with my server. Either the problem is my code is working on Flash Professional, but I have prepared all my interface on Flash Builder which uses Flex 4 -SDK. My code does not work on Flex Project.
The problem is not security file. I can not solve the problem. What are the possible reasons?
Kind Regards.
If necessary my code is below [working on FlashPro but not on Flex ! ]
import flash.net.*;
import flash.events.Event;var host:String = new String("127.0.0.1");
var port:int = 8080;
var securityFile:String = "http://localhost:1755/.../..../s....xml";
var bagli:Boolean = false;
var socket:Socket = null;
var veri:String = new String("----");
btnGonder.addEventListener(MouseEvent.MOUSE_DOWN, tiklantiEvent);
function buildSocket():void
{
trace("beginning....");
socket = new Socket();
socket.addEventListener(Event.CONNECT, onConnect);
socket.addEventListener(Event.CLOSE, onClose);
socket.addEventListener(ErrorEvent.ERROR, onError);
socket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
socket.addEventListener(ProgressEvent.SOCKET_DATA, onResponse);
Security.allowDomain(host);
Security.loadPolicyFile(securityFile);
try {
socket.connect(host, port);
bagli = true;
trace("--- connection...");
} catch (error:Error) {
trace("--- connection failed...");
socket.close();
}
}
function send(string:String):void {
socket.writeUTFBytes(string);
socket.flush();
}
function onConnect(event:Event):void {
trace("connect");
}
function onClose(event:Event):void {
trace("closed");
}
function onError(event:IOErrorEvent):void {
trace("connection erron");
}
function onIOError(event:IOErrorEvent):void {
trace("data error");
}
function onResponse(event:ProgressEvent):void {
var string:String = socket.readUTFBytes(socket.bytesAvailable);
trace(string);
}
function (sender:Event):void {
trace("clicked button....");
buildSocket();
trace("------------------");
}
You are trying to authorize a socket connection by using a content-type policy file. You should use socket policy file instead. Policy file syntax is the same as far as I remember, but the url should begin with xmlsocket:// instead of http://. This file should not be served through http.
Furthermore, the host's domain and the domain from the policy file address should be exactly the same. Given that your host is specified as 127.0.0.1, change the policy file url to
xmlsocket://127.0.0.1:1755
For more details see Adobe's guidelines for policy files.