All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.gravitee.am.gateway.handler.ciba.ad.impl.AuthenticationDeviceNotifierImpl Maven / Gradle / Ivy

There is a newer version: 4.6.0
Show newest version
/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed 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.
 */
package io.gravitee.am.gateway.handler.ciba.ad.impl;

import io.gravitee.am.gateway.handler.ciba.ad.AuthenticationDeviceNotifier;
import io.gravitee.am.gateway.handler.ciba.ad.model.ADNotificationRequest;
import io.gravitee.am.gateway.handler.ciba.ad.model.ADNotificationResponse;
import io.gravitee.am.gateway.handler.ciba.exception.DeviceNotificationException;
import io.gravitee.am.model.Domain;
import io.gravitee.am.service.http.WebClientBuilder;
import io.gravitee.common.http.HttpStatusCode;
import io.reactivex.rxjava3.core.Single;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.JsonObject;
import io.vertx.rxjava3.core.MultiMap;
import io.vertx.rxjava3.core.Vertx;
import io.vertx.rxjava3.ext.web.client.WebClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.net.URL;

/**
 * This class is a client to request Authentication Device interaction to an external HTTP backend.
 * This backend will be responsible for the user authentication and will call AM back to inform about the
 * user choice (ACCEPTED or REJECTED) regarding the authentication request.
 *
 * @author Eric LELEU (eric.leleu at graviteesource.com)
 * @author GraviteeSource Team
 */
public class AuthenticationDeviceNotifierImpl implements AuthenticationDeviceNotifier, InitializingBean {
    private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationDeviceNotifierImpl.class);
    public static final String TRANSACTION_ID = "tid";
    public static final String STATE = "state";
    public static final String PARAM_SUBJECT = "subject";
    public static final String PARAM_SCOPE = "scope";
    public static final String PARAM_EXPIRE = "expire";
    public static final String PARAM_ACR = "acr";
    public static final String PARAM_MESSAGE = "message";
    public static final String RESPONSE_ATTR_DATA = "data";
    public static final String URL_TO_GET_FROM_DOMAIN_SETTINGS = System.getProperty("ciba.ades", "http://localhost:8080/ciba/ades");

    @Autowired
    private Domain domain;

    @Autowired
    private Vertx vertx;

    @Autowired
    private WebClientBuilder clientBuilder;

    private WebClient client;

    @Override
    public void afterPropertiesSet() throws Exception {
        this.client = this.clientBuilder.createWebClient(vertx, new URL(URL_TO_GET_FROM_DOMAIN_SETTINGS)); // TODO configure in domain ciba settings or in a plugin, for testing get values from sysprop
    }

    @Override
    public Single notify(ADNotificationRequest request) {
        final MultiMap formData = MultiMap.caseInsensitiveMultiMap();

        formData.set(TRANSACTION_ID, request.getTransactionId());
        formData.set(STATE, request.getState());
        formData.set(PARAM_SUBJECT, request.getSubject());
        formData.set(PARAM_SCOPE, request.getScopes());
        formData.set(PARAM_EXPIRE, Integer.toString(request.getExpiresIn()));

        if (!CollectionUtils.isEmpty(request.getAcrValues())) {
            formData.set(PARAM_ACR, request.getAcrValues());
        }

        if (!StringUtils.isEmpty(request.getMessage())) {
            formData.set(PARAM_MESSAGE, request.getMessage());
        }

        return this.client.requestAbs(HttpMethod.POST, URL_TO_GET_FROM_DOMAIN_SETTINGS)
                .rxSendForm(formData)
                .doOnError((error) -> LOGGER.warn("Unexpected error during device notification : {}", error.getMessage(), error))
                .onErrorResumeNext(exception -> Single.error(new DeviceNotificationException("Unexpected error during device notification")))
                .map(response -> {
                    if (response.statusCode() != HttpStatusCode.OK_200) {
                        LOGGER.info("Device notification fails for tid '{}' with status '{}'", request.getTransactionId(), response.statusCode());
                        throw new DeviceNotificationException("Device notification fails");
                    }

                    final JsonObject result = response.bodyAsJsonObject();
                    if ( !request.getTransactionId().equals(result.getString(TRANSACTION_ID)) || !request.getState().equals(result.getString(STATE))) {
                        LOGGER.warn("Device notification response contains invalid tid or state", request.getTransactionId(), response.statusCode());
                        throw new DeviceNotificationException("Invalid device notification response");
                    }

                    final ADNotificationResponse notificationResponse = new ADNotificationResponse(request.getTransactionId());
                    if (result.containsKey(RESPONSE_ATTR_DATA)) {
                        notificationResponse.setExtraData(result.getJsonObject(RESPONSE_ATTR_DATA).getMap());
                    }
                    return notificationResponse;
        });
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy