blob: ebf42411f1bf7934799072b9a6390f938150ddf2 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to you under the Apache License, Version
2.0 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 Unless required by
applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for
the specific language governing permissions and limitations under the
License.
-->
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0">
<title>Adding BASIC Authentication</title>
<para>You probably don't want everybody in the world to connect to your service and access (and
update!) arbitrary data in the database. The first step in securing Cayenne service is
implementing client authentication. The easiest way to do it is to delegate the
authentication task to the web container that is running the service. HessianConnection used
in the previous chapter supports BASIC authentication on the client side, so we'll
demonstrate how to set it up here.</para>
<section xml:id="securing-rop-server-app">
<title>Securing ROP Server Application</title>
<para>Open web.xml file in the server project and setup security constraints with BASIC
authentication for the ROP service:</para>
<programlisting>&lt;security-constraint&gt;
&lt;web-resource-collection&gt;
&lt;web-resource-name&gt;CayenneService&lt;/web-resource-name&gt;
&lt;url-pattern&gt;/cayenne-service&lt;/url-pattern&gt;
&lt;/web-resource-collection&gt;
&lt;auth-constraint&gt;
&lt;role-name&gt;cayenne-service-user&lt;/role-name&gt;
&lt;/auth-constraint&gt;
&lt;/security-constraint&gt;
&lt;login-config&gt;
&lt;auth-method&gt;BASIC&lt;/auth-method&gt;
&lt;realm-name&gt;Cayenne Realm&lt;/realm-name&gt;
&lt;/login-config&gt;
&lt;security-role&gt;
&lt;role-name&gt;cayenne-service-user&lt;/role-name&gt;
&lt;/security-role&gt;</programlisting>
</section>
<section xml:id="configuring-jetty">
<title>Configuring Jetty for BASIC Authentication</title>
<para>
<note>
<para>These instructions are specific to Jetty 6. Other
containers (and versions of Jetty) will have different mechansims to achieve
the same thing.</para>
</note>
</para>
<para>Open pom.xml in the server project and configure a "userRealm" for the Jetty
plugin:</para>
<programlisting>&lt;plugin&gt;
&lt;groupId&gt;org.mortbay.jetty&lt;/groupId&gt;
&lt;artifactId&gt;maven-jetty-plugin&lt;/artifactId&gt;
&lt;version&gt;6.1.22&lt;/version&gt;
&lt;!-- adding configuration below: --&gt;
&lt;configuration&gt;
&lt;userRealms&gt;
&lt;userRealm implementation="org.mortbay.jetty.security.HashUserRealm"&gt;
&lt;!-- this name must match the realm-name in web.xml --&gt;
&lt;name&gt;Cayenne Realm&lt;/name&gt;
&lt;config&gt;realm.properties&lt;/config&gt;
&lt;/userRealm&gt;
&lt;/userRealms&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;</programlisting>
<para>Now create a new file called {["realm.properties"}} <emphasis role="italic">at the
root of the server project</emphasis> and put user login/password in there:</para>
<programlisting>cayenne-user: secret,cayenne-service-user</programlisting>
<para>.</para>
<para>Now let's stop the server and start it again. Everything should start as before, but
if you go to <emphasis role="italic"
>http://localhost:8080/tutorial/cayenne-service</emphasis>, your browser should pop
up authentication dialog. Enter "<emphasis role="italic">cayenne-user/secret</emphasis>"
for user name / password, and you should see "<emphasis role="italic">Hessian Requires
POST</emphasis>" message. So the server is now secured.</para>
</section>
<section xml:id="running-client">
<title>Running Client with Basic Authentication</title>
<para>If you run the client without any changes, you'll get the following error:</para>
<programlisting language="java">Mar 01, 2016 7:25:50 PM org.apache.cayenne.rop.http.HttpROPConnector logConnect
INFO: Connecting to [cayenne-user@http://localhost:8080/tutorial-rop-server/cayenne-service] - dedicated session.
Mar 01, 2016 7:25:50 PM org.apache.cayenne.rop.HttpClientConnection connect
INFO: Server returned HTTP response code: 401 for URL: http://localhost:8080/tutorial-rop-server/cayenne-service
java.rmi.RemoteException: Server returned HTTP response code: 401 for URL: http://localhost:8080/tutorial-rop-server/cayenne-service
at org.apache.cayenne.rop.ProxyRemoteService.establishSession(ProxyRemoteService.java:45)
at org.apache.cayenne.rop.HttpClientConnection.connect(HttpClientConnection.java:85)
at org.apache.cayenne.rop.HttpClientConnection.getServerEventBridge(HttpClientConnection.java:68)
at org.apache.cayenne.remote.ClientChannel.setupRemoteChannelListener(ClientChannel.java:279)
at org.apache.cayenne.remote.ClientChannel.&lt;init>(ClientChannel.java:71)
at org.apache.cayenne.configuration.rop.client.ClientChannelProvider.get(ClientChannelProvider.java:48)
at org.apache.cayenne.configuration.rop.client.ClientChannelProvider.get(ClientChannelProvider.java:31)
at org.apache.cayenne.di.spi.CustomProvidersProvider.get(CustomProvidersProvider.java:39)
at org.apache.cayenne.di.spi.FieldInjectingProvider.get(FieldInjectingProvider.java:43)
at org.apache.cayenne.di.spi.DefaultScopeProvider.get(DefaultScopeProvider.java:50)
at org.apache.cayenne.di.spi.DefaultInjector.getInstance(DefaultInjector.java:139)
at org.apache.cayenne.di.spi.FieldInjectingProvider.value(FieldInjectingProvider.java:105)
at org.apache.cayenne.di.spi.FieldInjectingProvider.injectMember(FieldInjectingProvider.java:68)
at org.apache.cayenne.di.spi.FieldInjectingProvider.injectMembers(FieldInjectingProvider.java:59)
at org.apache.cayenne.di.spi.FieldInjectingProvider.get(FieldInjectingProvider.java:44)
at org.apache.cayenne.di.spi.DefaultScopeProvider.get(DefaultScopeProvider.java:50)
at org.apache.cayenne.di.spi.DefaultInjector.getInstance(DefaultInjector.java:134)
at org.apache.cayenne.configuration.CayenneRuntime.newContext(CayenneRuntime.java:134)
at org.apache.cayenne.tutorial.persistent.client.Main.main(Main.java:44)</programlisting>
<para>Which is exactly what you'd expect, as the client is not authenticating itself. So
change the line in Main.java where we obtained an ROP connection to this:</para>
<programlisting language="java">Map&lt;String,String> properties = new HashMap&lt;>();
properties.put(Constants.ROP_SERVICE_URL_PROPERTY, "http://localhost:8080/tutorial/cayenne-service");
properties.put(Constants.ROP_SERVICE_USERNAME_PROPERTY, "cayenne-user");
properties.put(Constants.ROP_SERVICE_PASSWORD_PROPERTY, "secret");
ClientRuntime runtime = new ClientRuntime(properties);</programlisting>
<para>Try running again, and everything should work as before. Obviously in production
environment, in addition to authentication you'll need to use HTTPS to access the server
to prevent third-party eavesdropping on your password and data.</para>
<para>Congratulations, you are done with the ROP tutorial!</para>
</section>
</chapter>