/// <summary> /// Gets the certificate that should be used for client authentication /// </summary> /// <remarks> /// This method will throw an exception if the configuration properties used to /// look for the certificate are invalid. However, if the configuration is valid /// and no certificate is found, null will be returned and it is up to the caller /// to determine if an exception should be thrown in that case. /// </remarks> /// <exception cref="AdkTransportException">Thrown if the configuration properties used /// to look for the certificate are invalid or a certificate is found but /// it's certificate chain is invalid</exception> /// <returns>The certificate found or <c>null</c></returns> public Certificate GetClientAuthenticationCertificate() { HttpsProperties props = (HttpsProperties)fProps; Certificate cert = GetCertificateFromStore(OID_CLIENT_AUTHENTICATION, props.ClientCertName); if (cert == null) { return(null); } DebugTransport ("Using this certificate for Client Authentication: {0}", cert.ToString(true)); // ANDY E 07/26/2005 Removed the following code that verifies the chain of the certificate. // The reason is that the certificate doesn't really need to be trusted on this machine, // only on the machine that is receiving the certificate. Enabling the trust check here // makes configuration more difficult, and doesn't really help anything. If this code is // uncommented there will have to be more documentation added to the HTTPS documentation to // tell what all needs to be there for client certificates to be accepted by the ADK, especially // and specifically when an agent is running as a service. // CertificateStatus status = cert.GetCertificateChain().VerifyChain( null, AuthType.Client ); // // if ( status != CertificateStatus.ValidCertificate ) // { // log.Warn( "Certificate selected for client authentication is not valid: " + status.ToString() ); // return null; // } return(cert); }
/// <summary> /// Returns the system Certificate Store to retrieve certificates from /// </summary> /// <param name="props"></param> /// <returns></returns> private CertificateStore GetSystemStore(HttpsProperties props) { string certStoreLocation = props.CertStoreLocation; StoreLocation loc; if (certStoreLocation == null) { loc = StoreLocation.CurrentUser; } else { try { loc = (StoreLocation) Enum.Parse(typeof(StoreLocation), certStoreLocation, true); } catch { throw new AdkTransportException ("Invalid CertificateStore location: " + certStoreLocation, null); } } string certStoreName = props.CertStore; if (certStoreName == null) { certStoreName = CertificateStore.MyStore; } DebugTransport("Using Certificate store {0} / {1}", loc, certStoreName); return(new CertificateStore(loc, certStoreName)); }
/// <summary> /// Gets the certificate that should be used for server authentication ( SSL ) /// </summary> /// <remarks> /// This method will throw an exception if the configuration properties used to /// look for the certificate are invalid. However, if the configuration is valid /// and no certificate is found, null will be returned and it is up to the caller /// to determine if an exception should be thrown in that case. /// </remarks> /// <exception cref="AdkTransportException">Thrown if the configuration properties used /// to look for the certificate are invalid</exception> /// <returns>The certificate found or <c>null</c></returns> public Certificate GetServerAuthenticationCertificate() { HttpsProperties props = (HttpsProperties)fProps; Certificate cert = GetCertificateFromStore(OID_SERVER_AUTHENTICATION, props.SSLCertName); return(cert); }
/// <summary> Clone this HttpTransport. /// /// Cloning a transport results in a new HttpTransport instance with /// HttpProperties that inherit from this object's properties. However, the /// web server owned by this transport will be shared with the cloned /// instance. /// </summary> public ITransport CloneTransport() { HttpProperties props; if (fProps is HttpsProperties) { props = new HttpsProperties((HttpsProperties)fProps.Parent); } else { props = new HttpProperties((HttpProperties)fProps.Parent); } // This object and the clone share the server HttpTransport t = new HttpTransport(props, sServer); return(t); }
public void SetUpTest() { Adk.Debug = AdkDebugFlags.All; Adk.Initialize(); ServicePointManager.CertificatePolicy = new TestCertificatePolicy(); ServicePointManager.CheckCertificateRevocationList = false; //ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; fTransport = (HttpTransport)fAgent.TransportManager.GetTransport("https"); fProps = (HttpsProperties)fTransport.Properties; fProps.Port = 9000; fProps.CertStore = CERT_STORE; fProps.ClientAuthLevel = 0; fProps.ClientCertName = null; fZone = new TestZone(); fZone.Properties.MessagingMode = AgentMessagingMode.Push; }
private static NameValueCollection ParseAgentProperties(Agent agent) { // Parse all other options... AgentProperties props = agent.Properties; NameValueCollection misc = new NameValueCollection(); int port = -1; string host = null; bool useHttps = false; string sslCert = null; string clientCert = null; int clientAuth = 0; for (int i = 0; i < sArguments.Length; i++) { if (sArguments[i].ToUpper().Equals("/sourceId".ToUpper()) && i != sArguments.Length - 1) { agent.Id = sArguments[++i]; } else if (sArguments[i].ToUpper().Equals("/noreg".ToUpper())) { Reg = false; } else if (sArguments[i].ToUpper().Equals("/unreg".ToUpper())) { Unreg = true; } else if (sArguments[i].ToUpper().Equals("/pull".ToUpper())) { props.MessagingMode = AgentMessagingMode.Pull; } else if (sArguments[i].ToUpper().Equals("/push".ToUpper())) { props.MessagingMode = AgentMessagingMode.Push; } else if (sArguments[i].ToUpper().Equals("/port".ToUpper()) && i != sArguments.Length - 1) { try { port = Int32.Parse(sArguments[++i]); } catch (FormatException) { Console.WriteLine("Invalid port: " + sArguments[i - 1]); } } else if (sArguments[i].ToUpper().Equals("/https".ToUpper())) { useHttps = true; } else if (sArguments[i].ToUpper().Equals("/sslCert".ToUpper())) { sslCert = sArguments[++i]; } else if (sArguments[i].ToUpper().Equals("/clientCert".ToUpper())) { clientCert = sArguments[++i]; } else if (sArguments[i].ToUpper().Equals("/clientAuth".ToUpper())) { try { clientAuth = int.Parse(sArguments[++i]); } catch (FormatException) { clientAuth = 0; } } else if (sArguments[i].ToUpper().Equals("/host".ToUpper()) && i != sArguments.Length - 1) { host = sArguments[++i]; } else if (sArguments[i].ToUpper().Equals("/timeout".ToUpper()) && i != sArguments.Length - 1) { try { props.DefaultTimeout = TimeSpan.FromMilliseconds(Int32.Parse(sArguments[++i])); } catch (FormatException) { Console.WriteLine("Invalid timeout: " + sArguments[i - 1]); } } else if (sArguments[i].ToUpper().Equals("/freq".ToUpper()) && i != sArguments.Length - 1) { try { props.PullFrequency = TimeSpan.FromMilliseconds(int.Parse(sArguments[++i])); } catch (FormatException) { Console.WriteLine ("Invalid pull frequency: " + sArguments[i - 1]); } } else if (sArguments[i].ToUpper().Equals("/opensif".ToUpper())) { // OpenSIF reports attempts to re-subscribe to objects as an // error instead of a success status code. The Adk would therefore // throw an exception if it encountered the error, so we can // disable that behavior here. props.IgnoreProvisioningErrors = true; } else if (sArguments[i][0] == '/') { if (i == sArguments.Length - 1 || sArguments[i + 1].StartsWith("/")) { misc[sArguments[i].Substring(1)] = null; } else { misc[sArguments[i].Substring(1)] = sArguments[++i]; } } } if (useHttps) { // Set transport properties (HTTPS) HttpsProperties https = agent.DefaultHttpsProperties; if (sslCert != null) { https.SSLCertName = sslCert; } if (clientCert != null) { https.ClientCertName = clientCert; } https.ClientAuthLevel = clientAuth; if (port != -1) { https.Port = port; } https.Host = host; props.TransportProtocol = "https"; } else { // Set transport properties (HTTP) HttpProperties http = agent.DefaultHttpProperties; if (port != -1) { http.Port = port; } http.Host = host; props.TransportProtocol = "http"; } return(misc); }
/// <summary> Parse the command-line. This method may be called repeatedly, usually /// once from the sample agent's <c>main</code> function prior to /// initializing the Adk and again from the <c>Agent.initialize</code> /// method after initializing the Agent superclass. When called without an /// Agent instance, only those options that do not rely on an AgentProperties /// object are processed (e.g. the /D option). /// <p> /// * /// If a file named 'agent.rsp' exists in the current directory, any command /// line options specified will be appended to the command-line arguments /// passed to this method. Each line of the agent.rsp text file may be /// comprised of one or more arguments separated by spaces, so that the /// entirely set of arguments can be on one line or broken up onto many /// lines.<p> /// * /// </summary> /// <param name="agent">An Agent instance that will be updated when certain /// command-line options are parsed /// </param> /// <param name="arguments">The string of arguments provided by the <c>main</code> /// function /// /// </param> public static NameValueCollection parseCL(Agent agent, string[] arguments) { if (args == null) { args = arguments; if (args.Length > 0 && args[0][0] != '/') { // Look for an agent.rsp response file FileInfo rsp = new FileInfo(args[0]); if (rsp.Exists) { try { ArrayList v = new ArrayList(); using (StreamReader reader = File.OpenText(rsp.FullName)) { string line = null; while ((line = reader.ReadLine()) != null) { // allow comment lines, starting with a ; if (!line.StartsWith(";")) { foreach (string token in line.Split(' ')) { v.Add(token); } } } reader.Close(); } // Append any arguments found to the args array if (v.Count > 0) { args = new string[args.Length + v.Count]; Array.Copy(arguments, 0, args, 0, arguments.Length); v.CopyTo(args, arguments.Length); Console.Out.Write ("Reading command-line arguments from " + args[0] + ": "); for (int i = 0; i < args.Length; i++) { Console.Out.Write(args[i] + " "); } Console.WriteLine(); Console.WriteLine(); } } catch (Exception ex) { Console.WriteLine ("Error reading command-line arguments from agent.rsp file: " + ex); } } } } if (agent == null) { // Look for options that do not affect the AgentProperties... for (int i = 0; i < args.Length; i++) { if (args[i].ToUpper().Equals("/debug".ToUpper())) { if (i < args.Length - 1) { try { Adk.Debug = AdkDebugFlags.None; int k = Int32.Parse(args[++i]); if (k == 1) { Adk.Debug = AdkDebugFlags.Minimal; } else if (k == 2) { Adk.Debug = AdkDebugFlags.Moderate; } else if (k == 3) { Adk.Debug = AdkDebugFlags.Detailed; } else if (k == 4) { Adk.Debug = AdkDebugFlags.Very_Detailed; } else if (k == 5) { Adk.Debug = AdkDebugFlags.All; } } catch (Exception) { Adk.Debug = AdkDebugFlags.All; } } else { Adk.Debug = AdkDebugFlags.All; } } else if (args[i].StartsWith("/D")) { string prop = args[i].Substring(2); if (i != args.Length - 1) { Properties.SetProperty(prop, args[++i]); } else { Console.WriteLine("Usage: /Dproperty value"); } } else if (args[i].ToUpper().Equals("/log".ToUpper()) && i != args.Length - 1) { try { Adk.SetLogFile(args[++i]); } catch (IOException ioe) { Console.WriteLine("Could not redirect debug output to log file: " + ioe); } } else if (args[i].ToUpper().Equals("/ver".ToUpper()) && i != args.Length - 1) { Version = SifVersion.Parse(args[++i]); } else if (args[i].Equals("/?")) { Console.WriteLine(); Console.WriteLine ( "These options are common to all Adk Example agents. For help on the usage"); Console.WriteLine ( "of this agent in particular, run the agent without any parameters. Note that"); Console.WriteLine ( "most agents support multiple zones if a zones.properties file is found in"); Console.WriteLine("the current directory."); Console.WriteLine(); printHelp(); Environment.Exit(0); } } return(null); } // Parse all other options... AgentProperties props = agent.Properties; NameValueCollection misc = new NameValueCollection(); int port = -1; string host = null; bool useHttps = false; string sslCert = null; string clientCert = null; int clientAuth = 0; for (int i = 0; i < args.Length; i++) { if (args[i].ToUpper().Equals("/sourceId".ToUpper()) && i != args.Length - 1) { agent.Id = args[++i]; } else if (args[i].ToUpper().Equals("/noreg".ToUpper())) { Reg = false; } else if (args[i].ToUpper().Equals("/unreg".ToUpper())) { Unreg = true; } else if (args[i].ToUpper().Equals("/pull".ToUpper())) { props.MessagingMode = AgentMessagingMode.Pull; } else if (args[i].ToUpper().Equals("/push".ToUpper())) { props.MessagingMode = AgentMessagingMode.Push; } else if (args[i].ToUpper().Equals("/port".ToUpper()) && i != args.Length - 1) { try { port = Int32.Parse(args[++i]); } catch (FormatException) { Console.WriteLine("Invalid port: " + args[i - 1]); } } else if (args[i].ToUpper().Equals("/https".ToUpper())) { useHttps = true; } else if (args[i].ToUpper().Equals("/sslCert".ToUpper())) { sslCert = args[++i]; } else if (args[i].ToUpper().Equals("/clientCert".ToUpper())) { clientCert = args[++i]; } else if (args[i].ToUpper().Equals("/clientAuth".ToUpper())) { try { clientAuth = int.Parse(args[++i]); } catch (FormatException) { clientAuth = 0; } } else if (args[i].ToUpper().Equals("/host".ToUpper()) && i != args.Length - 1) { host = args[++i]; } else if (args[i].ToUpper().Equals("/timeout".ToUpper()) && i != args.Length - 1) { try { props.DefaultTimeout = TimeSpan.FromMilliseconds(Int32.Parse(args[++i])); } catch (FormatException) { Console.WriteLine("Invalid timeout: " + args[i - 1]); } } else if (args[i].ToUpper().Equals("/freq".ToUpper()) && i != args.Length - 1) { try { props.PullFrequency = TimeSpan.FromMilliseconds(int.Parse(args[++i])); } catch (FormatException) { Console.WriteLine("Invalid pull frequency: " + args[i - 1]); } } else if (args[i].ToUpper().Equals("/opensif".ToUpper())) { // OpenSIF reports attempts to re-subscribe to objects as an // error instead of a success status code. The Adk would therefore // throw an exception if it encountered the error, so we can // disable that behavior here. props.IgnoreProvisioningErrors = true; } else if (args[i][0] == '/') { if (i == args.Length - 1 || args[i + 1].StartsWith("/")) { misc[args[i].Substring(1)] = null; } else { misc[args[i].Substring(1)] = args[++i]; } } } if (useHttps) { // Set transport properties (HTTPS) HttpsProperties https = agent.DefaultHttpsProperties; if (sslCert != null) { https.SSLCertName = sslCert; } if (clientCert != null) { https.ClientCertName = clientCert; } https.ClientAuthLevel = clientAuth; if (port != -1) { https.Port = port; } https.Host = host; https.PushHost = host; props.TransportProtocol = "https"; } else { // Set transport properties (HTTP) HttpProperties http = agent.DefaultHttpProperties; if (port != -1) { http.Port = port; } http.Host = host; props.TransportProtocol = "http"; } return(misc); }
/// <summary> /// Returns the system Certificate Store to retrieve certificates from /// </summary> /// <param name="props"></param> /// <returns></returns> private CertificateStore GetSystemStore( HttpsProperties props ) { string certStoreLocation = props.CertStoreLocation; StoreLocation loc; if ( certStoreLocation == null ) { loc = StoreLocation.CurrentUser; } else { try { loc = (StoreLocation) Enum.Parse( typeof ( StoreLocation ), certStoreLocation, true ); } catch { throw new AdkTransportException ( "Invalid CertificateStore location: " + certStoreLocation, null ); } } string certStoreName = props.CertStore; if ( certStoreName == null ) { certStoreName = CertificateStore.MyStore; } DebugTransport( "Using Certificate store {0} / {1}", loc, certStoreName ); return new CertificateStore( loc, certStoreName ); }
/// <summary> Clone this HttpTransport. /// /// Cloning a transport results in a new HttpTransport instance with /// HttpProperties that inherit from this object's properties. However, the /// web server owned by this transport will be shared with the cloned /// instance. /// </summary> public ITransport CloneTransport() { HttpProperties props; if ( fProps is HttpsProperties ) { props = new HttpsProperties( (HttpsProperties) fProps.Parent ); } else { props = new HttpProperties( (HttpProperties) fProps.Parent ); } // This object and the clone share the server HttpTransport t = new HttpTransport( props, sServer ); return t; }
private Certificate GetCertificateFromStore(string oid, string certName) { HttpsProperties props = (HttpsProperties)fProps; // First, look for a file-based certificate, if specified in the props CertificateStore certStore = null; string certFile = props.SSLCertFile; if (certFile != null) { FileInfo info = new FileInfo(certFile); if (info.Exists) { if (info.Extension == ".pfx") { string cfp = props.SSLCertFilePassword; certStore = CertificateStore.CreateFromPfxFile(info.FullName, cfp); DebugTransport("Using certificate file '{0}'", info.FullName); } else { throw new AdkTransportException ("Certificate file must be in the .PFX format", null); } } else { throw new FileNotFoundException ("Unable to locate specified certificate file: " + certFile, certFile); } } if (certStore == null) { certStore = GetSystemStore(props); } Certificate cert = null; if (certName != null) { cert = certStore.FindCertificateBySubjectName(certName); } else { // Find the first applicable certificate foreach (Certificate c in certStore.EnumCertificates()) { if (!c.HasPrivateKey()) { DebugTransport ("Ignoring Certificate {0} because it has no private key", c.ToString(true)); continue; } if (!c.SupportsDataEncryption) { DebugTransport ("Ignoring Certificate {0} because it doesn't support data encryption", c.ToString(true)); continue; } if (c.GetEffectiveDate() > DateTime.Now) { DebugTransport ("Ignoring Certificate {0} because the effective date is in the future.", c.ToString(true)); continue; } if (c.GetExpirationDate() < DateTime.Now) { DebugTransport ("Ignoring Certificate {0} because it has expired", c.ToString(true)); continue; } StringCollection enhancedUsages = c.GetEnhancedKeyUsage(); if (enhancedUsages.Count > 0 && !enhancedUsages.Contains(oid)) { DebugTransport ("Ignoring Certificate {0} because it has an enhanced key usage attribute, that doesn't include {1}", c.ToString(true), oid); continue; } cert = c; break; } } return(cert); }