| <?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><security-constraint> |
| <web-resource-collection> |
| <web-resource-name>CayenneService</web-resource-name> |
| <url-pattern>/cayenne-service</url-pattern> |
| </web-resource-collection> |
| <auth-constraint> |
| <role-name>cayenne-service-user</role-name> |
| </auth-constraint> |
| </security-constraint> |
| |
| <login-config> |
| <auth-method>BASIC</auth-method> |
| <realm-name>Cayenne Realm</realm-name> |
| </login-config> |
| |
| <security-role> |
| <role-name>cayenne-service-user</role-name> |
| </security-role></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><plugin> |
| <groupId>org.mortbay.jetty</groupId> |
| <artifactId>maven-jetty-plugin</artifactId> |
| <version>6.1.22</version> |
| <!-- adding configuration below: --> |
| <configuration> |
| <userRealms> |
| <userRealm implementation="org.mortbay.jetty.security.HashUserRealm"> |
| <!-- this name must match the realm-name in web.xml --> |
| <name>Cayenne Realm</name> |
| <config>realm.properties</config> |
| </userRealm> |
| </userRealms> |
| </configuration> |
| </plugin> |
| </plugins></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.<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<String,String> properties = new HashMap<>(); |
| 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> |