1

I am trying to create protected Restlet resource based on this example http://bipinkunjumon.blogspot.com/2013/05/restlet-application-for-accessing.html:

public class PartApp extends Application {
public  static  final  String  ROOT_URI="localhost:8151/accounts/{accountId}";
public static void main(String[] args) throws Exception
{
    // Create a component
    Component component = new Component();
    component.getServers().add(Protocol.HTTP, 8151);
    component.getClients().add(Protocol.FILE);

    // Create an application
    Application application = new PartApp();

    // Attach the application to the component and start it
    component.getDefaultHost().attachDefault(application);
    component.start();
}

@Override
public Restlet createInboundRoot()
{
    // Create a simple password verifier
    MapVerifier verifier = new MapVerifier();
    verifier.getLocalSecrets().put("scott", "tiger".toCharArray());



    // Create a Guard
    ChallengeAuthenticator authenticator = new ChallengeAuthenticator(
            getContext(), ChallengeScheme.HTTP_BASIC, "Tutorial");
    authenticator.setVerifier(verifier);

    // Create a Directory able to return a deep hierarchy of files
    Directory directory = new Directory(getContext(), ROOT_URI);

    directory.setListingAllowed(true);
    authenticator.setNext(directory);
    return authenticator;
}
}

But it works for all server resources. For example, I am not able to enter localhost:8111 without login and password. But I need to protect only one resource: localhost:8151/accounts/{accountId} and to provide free access for another ones. How can I do that?

vitaliy4us
  • 483
  • 5
  • 21
  • Are you using tomcat to deploy restlet application? Or is it a standalone application? if you are using tomcat, then this link may help: http://stackoverflow.com/questions/10691490/how-do-i-configure-the-web-xml-for-multiple-restlet-applications – Abhishek Oza Jan 21 '17 at 08:22
  • No I am not using tomcat and despite the referenced example, all my resources belong to the same application. – vitaliy4us Jan 21 '17 at 13:33

1 Answers1

2

Based on the code I have found here: https://stackoverflow.com/a/2220624/444028 , I have made this tiny project using Java 7 and Restlet SE 2.3.9:

There are 6 java files (All are server side codes) in 2 packages in this project:

  1. package
    com.blogspot.javarestlet.httpbasicauth.server.app
    1. AdminAppStart.java (Application extension for authorized client)
    2. ClientAppStart.java (Application extension for unauthorized client) [Note: This is not the client side code.]
    3. Main.java (One that runs the server)
  2. package
    com.blogspot.javarestlet.httpbasicauth.server.resources
    1. HelloWorldAdminServerResource.java (To be attached with AdminAppStart)
    2. HelloWorldClientServerResource.java (To be attached with ClientAppStart)
    3. HelloWorldDefaultServerResource.java (A somewhat unnecessary class file)

Here is code of each file:

AdminAppStart.java

package com.blogspot.javarestlet.httpbasicauth.server.app;

import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Restlet;
import org.restlet.data.ChallengeScheme;
import org.restlet.routing.Router;
import org.restlet.security.ChallengeAuthenticator;
import org.restlet.security.MapVerifier;

import com.blogspot.javarestlet.httpbasicauth.server.resources.HelloWorldAdminServerResource;
import com.blogspot.javarestlet.httpbasicauth.server.resources.HelloWorldDefaultServerResource;

public class AdminAppStart extends Application {
    private ChallengeAuthenticator authenticator;

    private ChallengeAuthenticator createAuthenticator() {
        Context context = getContext();
        final boolean optional = false;
        ChallengeScheme challengeScheme = ChallengeScheme.HTTP_BASIC;
        String realm = "Example site";

        MapVerifier verifier = new MapVerifier();
        verifier.getLocalSecrets().put("scott", "tiger".toCharArray());

        ChallengeAuthenticator auth = new ChallengeAuthenticator(context, optional, challengeScheme, realm, verifier);
        return auth;
    }

    @Override
    public Restlet createInboundRoot() {
        this.authenticator = createAuthenticator();

        Router router = new Router();
        router.attach("/user", HelloWorldAdminServerResource.class);
        router.attach("", HelloWorldDefaultServerResource.class);

        authenticator.setNext(router);
        return authenticator;
    }

}

ClientAppStart.java

package com.blogspot.javarestlet.httpbasicauth.server.app;

import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.routing.Router;

import com.blogspot.javarestlet.httpbasicauth.server.resources.HelloWorldClientServerResource;

public class ClientAppStart extends Application {
@Override
public Restlet createInboundRoot() {
    Router router = new Router();
    router.attach("/clientres/hello", HelloWorldClientServerResource.class);
    return router;
}
}

Main.java

package com.blogspot.javarestlet.httpbasicauth.server.app;

import org.restlet.Application;
import org.restlet.Component;
import org.restlet.data.Protocol;

public class Main {
    public static void main(String[] args) throws Exception
    {
        // Create a component
        Component component = new Component();
        component.getServers().add(Protocol.HTTP, 8151);
        component.getClients().add(Protocol.HTTP);

        // Create an application
        Application application = new ClientAppStart();

        // Attach the application to the component and start it
        component.getDefaultHost().attach("/userx",application);
        component.getDefaultHost().attach("/admin/accounts/abc123",new AdminAppStart());
        component.start();
    }
}

HelloWorldAdminServerResource.java

package com.blogspot.javarestlet.httpbasicauth.server.resources;

import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class HelloWorldAdminServerResource  extends ServerResource {
    @Get
    public String $get()
    {
        return "Hello Admin";
    }
}

HelloWorldClientServerResource.java

package com.blogspot.javarestlet.httpbasicauth.server.resources;

import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class HelloWorldClientServerResource extends ServerResource {
@Get
public String $get()
{
    return "Hello Client";
}
}

HelloWorldDefaultServerResource.java

package com.blogspot.javarestlet.httpbasicauth.server.resources;

import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class HelloWorldDefaultServerResource extends ServerResource{
@Get
public String $get()
{
    return "please enter a sub-url after abc123";
}
}

Here is the cURL request-response log:

C:\Users\abhishek>curl -i "http://localhost:8151/userx/clientres/hello"
HTTP/1.1 200 OK
Content-type: text/plain; charset=UTF-8
Content-length: 12
Server: Restlet-Framework/2.3.9
Accept-ranges: bytes
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
Date: Mon, 23 Jan 2017 11:37:01 GMT

Hello Client

======================================================================

C:\Users\abhishek>curl -i -H "Authorization: Basic c2NvdHQ6dGlnZXI=" "http://localhost:8151/admin/accounts/abc123"
HTTP/1.1 200 OK
Content-type: text/plain; charset=UTF-8
Content-length: 35
Server: Restlet-Framework/2.3.9
Accept-ranges: bytes
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
Date: Mon, 23 Jan 2017 11:35:07 GMT

please enter a sub-url after abc123

======================================================================

C:\Users\abhishek>curl -i -H "Authorization: Basic c2NvdHQ6dGlnZXI=" "http://localhost:8151/admin/accounts/abc123/user"
HTTP/1.1 200 OK
Content-type: text/plain; charset=UTF-8
Content-length: 11
Server: Restlet-Framework/2.3.9
Accept-ranges: bytes
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
Date: Mon, 23 Jan 2017 11:35:04 GMT

Hello Admin

======================================================================

C:\Users\abhishek>curl -i "http://localhost:8151/admin/accounts/abc123/user"
HTTP/1.1 401 Unauthorized
Content-type: text/html; charset=UTF-8
Content-length: 424
Www-authenticate: Basic realm="Example site"
Server: Restlet-Framework/2.3.9
Accept-ranges: bytes
Date: Mon, 23 Jan 2017 12:48:08 GMT

<html>
<head>
   <title>Status page</title>
</head>
<body style="font-family: sans-serif;">
<p style="font-size: 1.2em;font-weight: bold;margin: 1em 0px;">Unauthorized</p>
<p>The request requires user authentication</p>
<p>You can get technical details <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">here</a>.<br>
Please continue your visit at our <a href="/">home page</a>.
</p>
</body>
</html>

Try this and tell us if you are facing any problem.

Added On 2017-01-24 1524:

Since the asker has asked "..Is this common rule to do things like this by creating separate applications..?"

Here is the answer to that question in simplest brief:

Application.createInboundRoot() is supposed to return Restlet and here are the subclasses of Restlet class obtained from here:https://restlet.com/technical-resources/restlet-framework/javadocs/2.3/jee/api/

org.restlet.Restlet
^
|
|--org.restlet.Application
|
|--org.restlet.Component
|
|--org.restlet.Connector
|  ^
|  |--org.restlet.Client
|  |
|  |--org.restlet.Server
|
|--org.restlet.routing.Filter
|  ^
|  |
|  |--org.restlet.security.Authenticator
|  |  ^
|  |  |
|  |  |--org.restlet.security.CertificateAuthenticator
|  |  |
|  |  |--org.restlet.security.ChallengeAuthenticator
|  |
|  |--org.restlet.security.Authorizer
|  |  ^
|  |  |
|  |  |--org.restlet.security.ConfidentialAuthorizer
|  |  |
|  |  |--org.restlet.security.MethodAuthorizer
|  |  |
|  |  |--org.restlet.security.RoleAuthorizer
|  |
|  |--org.restlet.routing.Extractor
|  |
|  |--org.restlet.routing.Route
|  |  ^
|  |  |
|  |  |--org.restlet.routing.TemplateRoute
|  |
|  |--org.restlet.routing.Validator
|
|--org.restlet.resource.Finder
|  ^
|  |
|  |--org.restlet.resource.Directory
|
|--org.restlet.routing.Redirector
|
|--org.restlet.routing.Router
|
|--org.restlet.util.WrapperRestlet

If you go through documentation and samples of each class (Each of it would make this answer too long), you will find that there are other ways of doing that, but creating separate Application for each is the easiest of all ways.

Community
  • 1
  • 1
Abhishek Oza
  • 3,340
  • 1
  • 27
  • 35
  • 1
    Thank you very much. It works for me. Is this the common rule to do things like this by creating a separate applications for the resources(like AdminAppStart and ClientAppStart in the example)? – vitaliy4us Jan 24 '17 at 07:01
  • And one more question concerning authorization. I created an application based on your example. I have protected route localhost:8151/accounts/{accountId} and a list of users with credentials: "user1", "user1"; "user2", "user2"; .... Users Ids are: 1, 2 ... . So each user's account could be reached by localhost:8151/accounts/1; ... . For example, I go to localhost:8151/accounts/1 and input credentials for the first user. Since that time any other accounts (e.g. localhost:8151/accounts/2) become accessible without any credentials. How to protect them? – vitaliy4us Jan 24 '17 at 13:45
  • @vitaliy4us what you will need here is a RoleAuthorizer. see these 2 links: 1. [Coarse-grained authorization](https://restlet.com/technical-resources/restlet-framework/guide/2.3/core/security/authorization), 2. [java - Creating a Restlet Authorizer for fine grained authorization](http://stackoverflow.com/questions/16499192/creating-a-restlet-authorizer-for-fine-grained-authorization) In the 1st link itself, you will find a combination of Authentication+Authorization – Abhishek Oza Jan 25 '17 at 05:48
  • Yes I saw this example [Coarse-grained authorization](https://restlet.com/technical-resources/restlet-framework/guide/2.3/core/security/authorization). But I can not make it working and even [posted a question about it](http://stackoverflow.com/questions/41780745/why-this-example-seems-to-be-not-working), but nobody answered. Is it realy working and displaying the responces in accordance with Resource0, Resource1 and Resource2 methods? – vitaliy4us Jan 25 '17 at 09:34
  • @vitaliy4us please take a look at my other answer [Abhishek Oza's answer to Restlet Authorization Filter](http://stackoverflow.com/a/14397323/444028). Try implementing that, if there is any problem, then tell us. – Abhishek Oza Jan 26 '17 at 07:02