org.eclipse.hono.service.credentials.CredentialsHttpEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.hono.service.credentials.CredentialsHttpEndpoint.java

Source

/**
 * Copyright (c) 2016, 2018 Red Hat and others
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Red Hat - initial creation
 */

package org.eclipse.hono.service.credentials;

import java.net.HttpURLConnection;
import java.util.Objects;

import io.vertx.core.http.HttpHeaders;
import org.eclipse.hono.config.ServiceConfigProperties;
import org.eclipse.hono.service.http.AbstractHttpEndpoint;
import org.eclipse.hono.util.CredentialsConstants;
import org.eclipse.hono.util.EventBusMessage;
import org.springframework.beans.factory.annotation.Autowired;

import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;

/**
 * An {@code HttpEndpoint} for managing device credentials.
 * <p>
 * This endpoint implements Hono's <a href="https://www.eclipse.org/hono/api/Credentials-API//">Credentials API</a>.
 * It receives HTTP requests representing operation invocations and sends them to the address {@link CredentialsConstants#CREDENTIALS_ENDPOINT} on the vertx
 * event bus for processing. The outcome is then returned to the client in the HTTP response.
 */
public final class CredentialsHttpEndpoint extends AbstractHttpEndpoint<ServiceConfigProperties> {

    // path parameters for capturing parts of the URI path
    private static final String PARAM_TYPE = "type";
    private static final String PARAM_AUTH_ID = "auth_id";

    /**
     * Creates an endpoint for a Vertx instance.
     *
     * @param vertx The Vertx instance to use.
     * @throws NullPointerException if vertx is {@code null};
     */
    @Autowired
    public CredentialsHttpEndpoint(final Vertx vertx) {
        super(Objects.requireNonNull(vertx));
    }

    @Override
    protected String getEventBusAddress() {
        return CredentialsConstants.EVENT_BUS_ADDRESS_CREDENTIALS_IN;
    }

    @Override
    public void addRoutes(final Router router) {

        final String pathWithTenant = String.format("/%s/:%s", CredentialsConstants.CREDENTIALS_ENDPOINT,
                PARAM_TENANT_ID);
        final String pathWithTenantAndDeviceId = String.format("/%s/:%s/:%s",
                CredentialsConstants.CREDENTIALS_ENDPOINT, PARAM_TENANT_ID, PARAM_DEVICE_ID);
        final String pathWithTenantAndAuthIdAndType = String.format("/%s/:%s/:%s/:%s",
                CredentialsConstants.CREDENTIALS_ENDPOINT, PARAM_TENANT_ID, PARAM_AUTH_ID, PARAM_TYPE);

        final BodyHandler bodyHandler = BodyHandler.create();
        bodyHandler.setBodyLimit(config.getMaxPayloadSize());

        // add credentials
        router.post(pathWithTenant).handler(bodyHandler);
        router.post(pathWithTenant).handler(this::extractRequiredJsonPayload);
        router.post(pathWithTenant).handler(this::addCredentials);

        // get credentials by auth-id and type
        router.get(pathWithTenantAndAuthIdAndType).handler(this::getCredentials);
        // get all credentials for a given device
        router.get(pathWithTenantAndDeviceId).handler(this::getCredentialsForDevice);

        // update credentials by auth-id and type
        router.put(pathWithTenantAndAuthIdAndType).handler(bodyHandler);
        router.put(pathWithTenantAndAuthIdAndType).handler(this::extractRequiredJsonPayload);
        router.put(pathWithTenantAndAuthIdAndType).handler(this::updateCredentials);

        // remove credentials by auth-id and type
        router.delete(pathWithTenantAndAuthIdAndType).handler(this::removeCredentials);
        // remove all credentials for a device
        router.delete(pathWithTenantAndDeviceId).handler(this::removeCredentialsForDevice);

    }

    private static String getTypeParam(final RoutingContext ctx) {
        return ctx.request().getParam(PARAM_TYPE);
    }

    private static String getAuthIdParam(final RoutingContext ctx) {
        return ctx.request().getParam(PARAM_AUTH_ID);
    }

    @Override
    public String getName() {
        return CredentialsConstants.CREDENTIALS_ENDPOINT;
    }

    private void addCredentials(final RoutingContext ctx) {

        final JsonObject payload = (JsonObject) ctx.get(KEY_REQUEST_BODY);
        final String deviceId = payload.getString(CredentialsConstants.FIELD_PAYLOAD_DEVICE_ID);
        final String authId = payload.getString(CredentialsConstants.FIELD_AUTH_ID);
        final String type = payload.getString(CredentialsConstants.FIELD_TYPE);
        final String tenantId = getTenantParam(ctx);
        logger.debug("adding credentials [tenant: {}, device-id: {}, auth-id: {}, type: {}]", tenantId, deviceId,
                authId, type);

        final JsonObject requestMsg = EventBusMessage
                .forOperation(CredentialsConstants.CredentialsAction.add.toString()).setTenant(tenantId)
                .setDeviceId(deviceId).setJsonPayload(payload).toJson();

        sendAction(ctx, requestMsg,
                getDefaultResponseHandler(ctx, status -> status == HttpURLConnection.HTTP_CREATED,
                        httpServerResponse -> httpServerResponse.putHeader(HttpHeaders.LOCATION,
                                String.format("/%s/%s/%s/%s", CredentialsConstants.CREDENTIALS_ENDPOINT, tenantId,
                                        authId, type))));
    }

    private void updateCredentials(final RoutingContext ctx) {

        final JsonObject payload = (JsonObject) ctx.get(KEY_REQUEST_BODY);
        final String deviceId = payload.getString(CredentialsConstants.FIELD_PAYLOAD_DEVICE_ID);
        final String authId = payload.getString(CredentialsConstants.FIELD_AUTH_ID);
        final String type = payload.getString(CredentialsConstants.FIELD_TYPE);
        final String tenantId = getTenantParam(ctx);
        final String authIdFromUri = getAuthIdParam(ctx);
        final String typeFromUri = getTypeParam(ctx);

        // auth-id and type from URI must match payload
        if (!authIdFromUri.equals(authId)) {
            ctx.response().setStatusMessage("Non-matching authentication identifier");
            ctx.fail(HttpURLConnection.HTTP_BAD_REQUEST);
        } else if (!typeFromUri.equals(type)) {
            ctx.response().setStatusMessage("Non-matching credentials type");
            ctx.fail(HttpURLConnection.HTTP_BAD_REQUEST);
        } else {
            logger.debug("updating credentials [tenant: {}, device-id: {}, auth-id: {}, type: {}]", tenantId,
                    deviceId, authId, type);

            final JsonObject requestMsg = EventBusMessage
                    .forOperation(CredentialsConstants.CredentialsAction.update.toString()).setTenant(tenantId)
                    .setDeviceId(deviceId).setJsonPayload(payload).toJson();

            sendAction(ctx, requestMsg, getDefaultResponseHandler(ctx));
        }
    }

    private void removeCredentials(final RoutingContext ctx) {

        final String tenantId = getTenantParam(ctx);
        final String type = getTypeParam(ctx);
        final String authId = getAuthIdParam(ctx);

        logger.debug("removeCredentials [tenant: {}, type: {}, authId: {}]", tenantId, type, authId);

        final JsonObject payload = new JsonObject();
        payload.put(CredentialsConstants.FIELD_TYPE, type);
        payload.put(CredentialsConstants.FIELD_AUTH_ID, authId);

        final JsonObject requestMsg = EventBusMessage
                .forOperation(CredentialsConstants.CredentialsAction.remove.toString()).setTenant(tenantId)
                .setJsonPayload(payload).toJson();

        sendAction(ctx, requestMsg,
                getDefaultResponseHandler(ctx, status -> status == HttpURLConnection.HTTP_NO_CONTENT, null));
    }

    private void removeCredentialsForDevice(final RoutingContext ctx) {

        final String tenantId = getTenantParam(ctx);
        final String deviceId = getDeviceIdParam(ctx);

        logger.debug("removeCredentialsForDevice: [tenant: {}, device-id: {}]", tenantId, deviceId);

        final JsonObject payload = new JsonObject();
        payload.put(CredentialsConstants.FIELD_PAYLOAD_DEVICE_ID, deviceId);
        payload.put(CredentialsConstants.FIELD_TYPE, CredentialsConstants.SPECIFIER_WILDCARD);

        final JsonObject requestMsg = EventBusMessage
                .forOperation(CredentialsConstants.CredentialsAction.remove.toString()).setTenant(tenantId)
                .setDeviceId(deviceId).setJsonPayload(payload).toJson();

        sendAction(ctx, requestMsg,
                getDefaultResponseHandler(ctx, status -> status == HttpURLConnection.HTTP_NO_CONTENT, null));
    }

    /**
     * Gets credentials by auth-id and type.
     * 
     * @param ctx The context to retrieve the query parameters from.
     */
    private void getCredentials(final RoutingContext ctx) {

        // mandatory params
        final String tenantId = getTenantParam(ctx);
        final String authId = getAuthIdParam(ctx);
        final String type = getTypeParam(ctx);

        logger.debug("getCredentials [tenant: {}, auth-id: {}, type: {}]", tenantId, authId, type);

        final JsonObject requestMsg = CredentialsConstants.getServiceGetRequestAsJson(tenantId, null, authId, type);

        sendAction(ctx, requestMsg,
                getDefaultResponseHandler(ctx, status -> status == HttpURLConnection.HTTP_OK, null));

    }

    private void getCredentialsForDevice(final RoutingContext ctx) {

        // mandatory params
        final String tenantId = getTenantParam(ctx);
        final String deviceId = getDeviceIdParam(ctx);

        logger.debug("getCredentialsForDevice [tenant: {}, device-id: {}]]", tenantId, deviceId);

        final JsonObject requestMsg = CredentialsConstants.getServiceGetRequestAsJson(tenantId, deviceId, null,
                CredentialsConstants.SPECIFIER_WILDCARD);

        sendAction(ctx, requestMsg,
                getDefaultResponseHandler(ctx, status -> status == HttpURLConnection.HTTP_OK, null));
    }

}