I am writing a REST web service using Jersey, and I'm trying to write a set of unit tests to test the service using the Jersey Test Framework.
However, I use HTTP Authentication and SecurityContext as part of my web service, and I'm having issues setting up JTF to allow me to test these aspects. I can send authentication information in the request, but how do I configure it to know about the different roles and users I wish to set up?
I'm currently using Jetty (via JettyTestContainerFactory), but can switch to different test containers if needed.
The specific configuration I am trying to achieve is two roles, and four users with the combinations of those possible roles (e.g. No roles, role a, role b, roles a and b). The web service will handle giving access to different URLs, so that doesn't need to be specified in the configuration.
I have done this by implementing my own Jetty Test container similar to the one provided by Jersey. We use an embedded Jetty for testing our application in development normally and by creating our own test container based on that embedded Jetty it loads our web application as it would if it was started by a Java main process.
We use a custom Jetty Security Handler configured in a jetty-env.xml file which the embedded Jetty uses to configure the security.
<Set name="securityHandler">
<New class="com.example.DevelopmentSecurityHandler">
<Set name="loginService">
<New class="com.example.DevelopmentLoginService">
<Set name="name">LocalRealm</Set>
<Set name="config">src/main/webapp/WEB-INF/users.properties</Set>
<Call name="start" />
</New>
</Set>
<Set name="authenticator">
<New class="com.example.DevelopmentAuthenticator"></New>
</Set>
<Set name="checkWelcomeFiles">true</Set>
</New>
</Set>
That Jetty env file is loaded by embedded Jetty:
XmlConfiguration configuration = null;
if (jettyEnvFile.exists()) {
try {
configuration = new XmlConfiguration(jettyEnvFile.toURI().toURL());
} catch (Exception e) {
throw new ProcessingException(String.format("Exception loading jetty config from %s", jettyEnvFile));
}
} else {
LOG.warn("No jetty-env.xml found.");
}
The users.properties file referenced in that xml is a simple user to role mapping e.g.
USERNAME=PASSWORD,ROLE_NAME1,ROLE_NAME2
Depending how you configure your Jetty security this may or may not work for you. You can also configure this programmatically, there's lots of examples of embedded Jetty here. The SecuredHelloHandler.java example there could be a good start for you.
For the test container you can basically start by copying org.glassfish.jersey.test.jetty.JettyTestContainerFactory and org.glassfish.jersey.jetty.JettyHttpContainerFactory essentially changing the
public static Server createServer(final URI uri, final SslContextFactory sslContextFactory, final JettyHttpContainer handler, final boolean start)
method to create your version of an embedded Jetty server with security configured however you require.
Related
The issue I have is we currently are using IdentityServer as our SSO authentication for our corporate applications. However, the bulk of our applications are under the same Site ID in IIS 7.5. When navigating to more than 5 of these applications under the same Site ID, you end up getting a 400 error, request header too long. The reason being each application has its own cookie, so the request header is passing around 5+ cookies with token information and the becoming too large.
My question is, are you able to prevent the sharing of cookies between applications under the same Site ID in IIS 7.5?
We also have IdentityServer for SSO and internal applications hosted on the same machine on IIS.
And I faced with the same problem too.
Here is a solution:
1) You need to solve Owin/Katana middleware problem to avoid nonce overfloating. Here you can find the code for that fix
2) You have to stop sharing cookies.
So if your base address for applications is "mysite.com".
And you have a lot of different applications like this:
Good App: mysite.com/good_app/
Best App: mysite.com/best_app/
Super App: mysite.com/super_app/
Use CookiePath for each application on an application's side and it will limit cookies (and look here too).
Use the code like this (for "Good App"):
var cookieOptions = new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
CookieName = "GoodAppCookies",
// Cookie Path same as application name on IIS
CookiePath = "/good_app
};
Hope it'll help.
Few things that you can try. Make the following changes at the server level.
Highlight the server name in IIS, select "configuration editor", select "system.web" and "httpRuntime" and change "maxRequestLength" to "1048576".
You can also edit the "applicationHost.config" file in the following way- C:\Windows\System32\inetsrv\Config
<configuration>
<system.web>
<httpRuntime maxRequestLength="1048576" />
</system.web>
</configuration>
Edit "Request Filtering" settings at server level on IIS and set "maxAllowedContentLength" to "1073741824"
You can also edit the root web.config file in the following manner - C:\Windows\Microsoft.NET\Framework64*\v4.0.30319*\Config
*Folder is based on your application. if its a 32 bit application, navigate to "Framework" folder. If its a .net 2.0 application, navigate to v2.0.50727.
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
</system.webServer>
First of all - I want to say that I have not tried this myself, so I can't assure that it is a solution, but I'm trying to help.
The problem with the cookies originates from the Microsoft OWIN/Katana and the way they are encrypting them. They become enormous, but this has nothing to do with Identity Server. However here and here there are good discussion around this.
The main thing to try first is in the Startup.cs of the IdentityServer project, in the IdentityServerOptions.AuthenticationOptions there is a property SignInMessageThreshold which defaults to 5. Try setting it to something lower, this will keep your header smaller (which may cause round trips to identity server when an app doesn't have its message in the cookies, but this will not force the user to re-login).
Another thing, that we achieved in one of out projects, is to create a DataBase backed cookie session handler. In your clients, where you use
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
CookieName = cookieName,
});
There is also a property SessionStore. You can have a custom implementation of the Microsoft.Owin.Security.Cookies.IAuthenticationSessionStore. In our case this reduced the cookie size to less than (or around) 300.
After successfully developing an application with multiple ServiceStack services, we are moving to other testing environments, lots of them due to us running a SAAS model (aka multi-tenant). I'd like to reuse some of the base infrastructure services, primarily Redis and RabbitMQ across a few of these environments.
We're using the IAppSetting interface to pull our configuration from multiple sources into one cohesive settings object at run-time, which is then filtered tier. Since tier drives the configuration per environment it made sense to use Tier to prefix any RabbitMQ messages queues, and prefix any generated cache keys that will be used by Redis, thus providing collision protection per environment.
Below is an example:
RabbitMQ => "Some MQ method here" => "mq:qa1.Outbound.inq"
Redis => "Some Redis method here" => "urn:qa1.somePoco:123"
Here is an example configuration and the various enviroments
<appSettings>
<add key="Tier" value="qa1" />
<!--<add key="Tier" value="dev" />-->
<!--<add key="Tier" value="tst" />-->
<!--<add key="Tier" value="stg" />-->
<!--<add key="Tier" value="prod" />-->
</appSettings>
Thank you,
Stephen
Some examples on how to modify Queue Names are in MqNameTests, e.g:
QueueNames.SetQueuePrefix("site1.");
Will add a prefix on QueueNames, e.g:
site1.mq:TestPrefix.inq
Otherwise you can use QueueNames.ResolveQueueNameFn to have complete control over the MQ name, e.g:
QueueNames.ResolveQueueNameFn = (typeName, suffix) =>
"SITE.{0}{1}".Fmt(typeName, suffix.ToUpper());
QueueNames<TestFilter>.In.Print(); // SITE.TestFilter.INQ
Note the same configuration also needs to applied on the client so the same MQ names gets used.
Configuring ServiceStack with AppSettings
ServiceStack is a code-first framework which means all configuration is done in code, but has a rich and versatile configuration model where you can get the behavior your after by reading App Settings in AppHost.Configure():
QueueNames.SetQueuePrefix(AppSettings.Get("Tier","dev"));
Where if Tier doesn't exist in your Web.config (e.g. in Unit Tests) it will use dev otherwise will use the value in your appSettings:
<appSettings>
<add key="Tier" value="qa1" />
</appSettings>
The context
Two nodes of a Hazelcast cluster, each on a discrete subnet so multicast is not suitable nor working for node location.
I should like to employ the most minimal XML configuration file, say hazelcast.xml, to configure Hazelcast to use TCP/IP to connect the two nodes. Ideally a directory of the IP addresses of the two nodes.
The question
The Hazelcast docs do a good job of showing how this can be achieved programatically, and how hazelcast.jar/hazelcast-default.xml holds the (considerable) default configuration.
What is unclear is: is any XML configuration I supply overlaid upon the settings within hazelcast-default.xml - or simply used in its stead?
I have both my answers, and should like to share them
Just like the programatic API, the XML configuration overlays the defaults found in hazelcast.jar/hazelcast-default.xml, consequently ...
I can establish a very simple two-member cluster with this hazelcast.xml in the classpath
<hazelcast>
<network>
<join>
<multicast enabled="false"></multicast>
<tcp-ip enabled="true">
<member>192.168.100.001</member> <!-- server A -->
<member>192.168.102.200</member> <!-- server B, on separate subnet -->
</tcp-ip>
</join>
</network>
</hazelcast>
I'm not familiar with hazelcast.conf files.
Mostly used is XML or Programmatic api. For good examples see:
https://github.com/hazelcast/hazelcast-code-samples/tree/master/network-configuration
Example of programmatic:
public class Main {
public static void main(String[] args){
Config config = new Config();
config.getNetworkConfig().getJoin().getTcpIpConfig().addMember("localhost").setEnabled(true);
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
HazelcastInstance hz = Hazelcast.newHazelcastInstance(config);
}
}
--
What is unclear is: is any XML configuration I supply overlaid upon the settings within hazelcast-default.xml - or simply used in its stead?
What do you mean? If you use the programmatic API, the rest is not relevant. If you don't provide an explicit Config object while constructing the HazelcastInstance, a defaulting mechanism is used. And eventually it defaults to hazelcast-default.xml.
I am having trouble with configuring a webapp in Tomcat 7. In my WAR file, there is a properties file myApp/WEB-INF/classes/myProps.props, and it contains environment-specific properites. I am trying to override that configuration file on the server, so that the same WAR file will deploy to multiple environments.
I heard there was a way to do this using replacement config files in tomcat/conf/Catalina/myApp. This is the method I am having trouble figuring out.
Also, myApp.war is one of many running on the same Tomcat server, and it does not run as localhost. I want to be able to solve this problem for several of the webapps.
Server version: Apache Tomcat/7.0.23
Server built: Nov 20 2011 07:36:25
Server number: 7.0.23.0
OS Name: Linux
Your tomcat/conf/Catalina/<host> can contain context descriptors that let you configure lots of things including defining "environment entries", which are accessible from Java via JNDI. There are lots of ways to go about using it. Personally, I set an environment entry which is the file system path to my properties file. My app is built to check for this entry, and if it doesn't exist, look for the file on the classpath instead. That way, in dev, we have the dev properties right there on the classpath, but when we build and deploy, we point it to an external file.
There's good documentation for configuring a context on the Tomcat website. See the Defining a Context section on details of how to create the file and where to put it.
As an example, if your host is named myHost and your app is a war file named myApp.war in the webapps directory, then you could create tomcat/conf/Catalina/myHost/myApp.xml with this content:
<Context>
<Environment name="configurationPath" value="/home/tomcat/myApp.properties" type="java.lang.String"/>
</Context>
Then from your code, you'd do a JNDI lookup on java:comp/env/configurationPath (95% certainty here) to get that string value.
I like .properties files instead of
JNDI - why build complex object during program configuration instead of initialization time?
system properties - you can't separately configure several instances of same WAR in single Tomcat
context parameters - they accessible only in javax.servlet.Filter, javax.servlet.ServletContextListener which my be inconvenient
Tomcat 7 Context hold Loader element. According to docs deployment descriptor (what in <Context> tag) can be placed in:
$CATALINA_BASE/conf/server.xml - bad - require server restarts in order to reread config
$CATALINA_BASE/conf/context.xml - bad - shared across all applications
$CATALINA_BASE/work/$APP.war:/META-INF/context.xml - bad - require repackaging in order to change config
$CATALINA_BASE/work/[enginename]/[hostname]/$APP/META-INF/context.xml - nice, but see last option!!
$CATALINA_BASE/webapps/$APP/META-INF/context.xml - nice, but see last option!!
$CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml - best - completely out of application and automatically scanned for changes!!!
Context can hold custom Loader org.apache.catalina.loader.VirtualWebappLoader (available in modern Tomcat 7, you can add own separate classpath to your .properties), and Parameter (accessed via FilterConfig.getServletContext().getInitParameter(name)) and Environment (accessed via new InitialContext().lookup("java:comp/env").lookup("name")):
<Context docBase="${basedir}/src/main/webapp"
reloadable="true">
<!-- http://tomcat.apache.org/tomcat-7.0-doc/config/context.html -->
<Resources className="org.apache.naming.resources.VirtualDirContext"
extraResourcePaths="/WEB-INF/classes=${basedir}/target/classes,/WEB-INF/lib=${basedir}/target/${project.build.finalName}/WEB-INF/lib"/>
<Loader className="org.apache.catalina.loader.VirtualWebappLoader"
virtualClasspath="${basedir}/target/classes;${basedir}/target/${project.build.finalName}/WEB-INF/lib"/>
<JarScanner scanAllDirectories="true"/>
<Parameter name="min" value="dev"/>
<Environment name="app.devel.ldap" value="USER" type="java.lang.String" override="true"/>
<Environment name="app.devel.permitAll" value="true" type="java.lang.String" override="true"/>
</Context>
If you use Spring and it's XML config:
<context:property-placeholder location="classpath:app.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#${db.host}:${db.port}:${db.user}"/>
<property name="username" value="${db.user}"/>
<property name="password" value="${db.pass}"/>
</bean>
With Spring injecting above properties into bean fields are easy:
#Value("${db.user}") String defaultSchema;
instead of JNDI:
#Inject ApplicationContext context;
Enviroment env = context.getEnvironment();
String defaultSchema = env.getProperty("db.user");
Note also that EL allow this (default values and deep recursive substitution):
#Value('${db.user:testdb}') private String dbUserName;
<property name='username' value='${db.user.${env}}'/>
See also:
Adding a directory to tomcat classpath
Can I create a custom classpath on a per application basis in Tomcat
How to read a properties file outside my webapp context in Tomcat
Configure Tomcat to use properties file to load DB connection information
Should you set up database connection properties in server.xml or context.xml
Externalize Tomcat configuration
NOTE With extending classpath to live directory you also allowed to externilize any other configs, like logging, auth, atc. I externilize logback.xmlin such way.
UPDATE Tomcat 8 change syntax for <Resources> and <Loader> elements, corresponding part now look like:
<Resources>
<PostResources className="org.apache.catalina.webresources.DirResourceSet"
webAppMount="/WEB-INF/classes" base="${basedir}/target/classes" />
<PostResources className="org.apache.catalina.webresources.DirResourceSet"
webAppMount="/WEB-INF/lib" base="${basedir}/target/${project.build.finalName}/WEB-INF/lib" />
</Resources>
You can try to place your configuration (properties file) in Apache Tomcat\lib in JAR file and remove it from the web application. When the Tomcat's class loader won't find your config in webapp it will try to find in "lib" directory. So you can externalize your configuration just moving the config to global lib dir (it's shared among other webapps).
I just added a setenv.bat or setenv.sh script in the bin folder of tomcat. Set the classpath variable like
set CLASSPATH=my-propery-folder
I have moderate experience in developing web applications using spring.net 4.0 , nhibernate 3.0 for ASP.net based web applications. Recently I ran into a situation where I needed to use spring.net to inject my service dependencies which belong to the WorkerRole class. I created the app.config file as I normally did with the web.config files on for spring. Here it is for clarity. (I have excluded the root nodes)
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web" requirePermission="false" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" requirePermission="false" />
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<!-- Application services and data access that has been previously developed and tested-->
<resource uri="assembly://DataAccess/data-access-config.xml" />
<resource uri="assembly://Services/service-config.xml" />
<resource uri="AOP.xml" />
<resource uri="DI.xml"/>
</context>
<parsers>
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
<parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data" />
<parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" />
</parsers>
</spring>
Similarly Here's the AOP.xml
<object id="FilterServiceProxy" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="proxyInterfaces" value="Domain.IFilterService"/>
<property name="target" ref="FilterService"/>
<property name="interceptorNames">
<list>
<value>UnhandledExceptionThrowsAdvice</value>
<value>PerformanceLoggingAroundAdvice</value>
</list>
</property>
</object>
</objects>
and the DI.xml
<object type="FilterMt.WorkerRole, FilterMt" >
<property name="FilterMtService1" ref="FilterServiceProxy"/>
</object>
However, I was unable to inject any dependencies into the worker role. Can someone please let me know what I am doing wrong here ? Is there a different way to configure Spring.net DI for windows azure applications ?
I don't get any configuration errors but I see that the dependencies have not been injected because the property object to which I've tried injection, remains null.
Based on my experience, you cannot inject anything into your WorkerRole class (the class that implements RoleEntryPoint). What I do, so far with Unity (I also built my own helper for Unity to help me inject Azure settings), is that I have my own infrastructure that runs and is built by Unity, but I create it in the code for the worker role.
For example, I initialize the dependency container in my OnStart() method of RoleEntry point, where I resolve anything I need. Then in my Run() method I call a method on my resolved dependency.
Here is a quick, stripped off version of my RoleEntryPoint's implementation:
public class WorkerRole : RoleEntryPoint
{
private UnityServiceHost _serviceHost;
private UnityContainer _container;
public override void Run()
{
// This is a sample worker implementation. Replace with your logic.
Trace.WriteLine("FIB.Worker entry point called", "Information");
using (this._container = new UnityContainer())
{
this._container.LoadConfiguration();
IWorker someWorker = this._container.Resolve<IWorker>();
someWorker.Start();
IWorker otherWorker = this._container.Resolve<IWorker>("otherWorker");
otherWorker.Start();
while (true)
{
// sleep 30 minutes. we don't really need to do anything here.
Thread.Sleep(1800000);
Trace.WriteLine("Working", "Information");
}
}
}
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
// For information on handling configuration changes
// see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
this.CreateServiceHost();
return base.OnStart();
}
public override void OnStop()
{
this._serviceHost.Close(TimeSpan.FromSeconds(30));
base.OnStop();
}
private void CreateServiceHost()
{
this._serviceHost = new UnityServiceHost(typeof(MyService));
var binding = new NetTcpBinding(SecurityMode.None);
RoleInstanceEndpoint externalEndPoint =
RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["ServiceEndpoint"];
string endpoint = String.Format(
"net.tcp://{0}/MyService", externalEndPoint.IPEndpoint);
this._serviceHost.AddServiceEndpoint(typeof(IMyService), binding, endpoint);
this._serviceHost.Open();
}
As you can see, my own logic is IWorker interface and I can have as many implementations as I want, and I instiate them in my Run() method. What I do more is to have a WCF Service, again entirely configured via DI with Unity. Here is my IWorker interface:
public interface IWorker : IDisposable
{
void Start();
void Stop();
void DoWork();
}
And that's it. I don't have any "hard" dependencies in my WorkerRole, just the Unity Container. And I have very complex DIs in my two workers, everything works pretty well.
The reason why you can't interfere directly with your WorkerRole.cs class, is that it is being instantiated by the Windows Azure infrastructure, and not by your own infrastructure. You have to accept that, and built your infrastructure within the WorkerRole appropriate methods. And do not forget that you must never quit/break/return/exit the Run() method. Doing so will flag Windows Azure infrastructure that there is something wrong with your code and will trigger role recycling.
Hope this helps.
I know this is an old question, but I'm going through the same learning curve and would like to share my findings for someone who struggles to understand the mechanics.
The reason you can't access DI in your worker role class is because this is run in a separate process in the OS, outside of IIS. Think of your WebRole class as being run in a Windows Service.
I've made a little experiment with my MVC web-site and WebRole class:
public class WebRole : RoleEntryPoint
{
public override void Run()
{
while (true)
{
Thread.Sleep(10000);
WriteToLogFile("Web Role Run: run, Forest, RUN!");
}
}
private static void WriteToLogFile(string text)
{
var file = new System.IO.StreamWriter("D:\\tmp\\webRole.txt", true); // might want to change the filename
var message = string.Format("{0} | {1}", DateTime.UtcNow, text);
file.WriteLine(message);
file.Close();
}
}
This would write to a file a new string every 10 seconds (or so). Now start your Azure site in debugging mode, make sure the site deployed to Azure emulator and the debugger in VS has started. Check that the site is running and check that WebRole is writing to the file in question.
Now stop the IIS Express (or IIS if you are running it in full blown installation) without stopping the VS debugger. All operations in your web-site are stopped now. But if you check your temp file, the process is still running and you still get new lines added every 10 seconds. Until you stop the debugger.
So whatever you have loaded in memory of web-application is inside of the IIS and not available inside of Worker Role. And you need to re-configure your DI and other services from the scratch.
Hope this helps someone to better understand the basics.