nl.surfnet.coin.janus.JanusRestClient.java Source code

Java tutorial

Introduction

Here is the source code for nl.surfnet.coin.janus.JanusRestClient.java

Source

/*
 * Copyright 2012 SURFnet bv, The Netherlands
 *
 * 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 nl.surfnet.coin.janus;

import nl.surfnet.coin.janus.domain.ARP;
import nl.surfnet.coin.janus.domain.EntityMetadata;
import nl.surfnet.coin.janus.domain.JanusEntity;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Transformer;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * REST client implementation for Janus.
 */
public class JanusRestClient implements Janus {

    private static Logger LOG = LoggerFactory.getLogger(JanusRestClient.class);

    private RestTemplate restTemplate;

    private URI janusUri;

    private String user;

    private String secret;

    public JanusRestClient() {
        this.restTemplate = new RestTemplate();
        restTemplate.setMessageConverters(
                Arrays.<HttpMessageConverter<?>>asList(new MappingJacksonHttpMessageConverter()));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public EntityMetadata getMetadataByEntityId(String entityId) {
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put("entityid", entityId);
        final Collection metadataAsStrings = CollectionUtils.collect(Arrays.asList(Metadata.values()),
                new Transformer() {
                    @Override
                    public Object transform(Object input) {
                        return ((Metadata) input).val();
                    }
                });

        parameters.put("keys", StringUtils.join(metadataAsStrings, ','));

        URI signedUri;
        try {
            signedUri = sign("getMetadata", parameters);

            if (LOG.isTraceEnabled()) {
                LOG.trace("Signed Janus-request is: {}", signedUri);
            }

            @SuppressWarnings("unchecked")
            final Map<String, Object> restResponse = restTemplate.getForObject(signedUri, Map.class);
            Assert.notNull(restResponse, "Rest response from Janus should not be null");

            if (LOG.isTraceEnabled()) {
                LOG.trace("Janus-request returned: {}", restResponse.toString());
            }

            final EntityMetadata entityMetadata = EntityMetadata.fromMetadataMap(restResponse);

            entityMetadata.setAppEntityId(entityId);
            return entityMetadata;
        } catch (IOException e) {
            LOG.error("While doing Janus-request", e);
        }
        return null;
    }

    @Override
    public List<String> getEntityIdsByMetaData(Metadata key, String value) {
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put("key", key.val());
        parameters.put("value", value);

        URI signedUri;
        try {
            signedUri = sign("findIdentifiersByMetadata", parameters);

            if (LOG.isTraceEnabled()) {
                LOG.trace("Signed Janus-request is: {}", signedUri);
            }

            @SuppressWarnings("unchecked")
            final List<String> restResponse = restTemplate.getForObject(signedUri, List.class);

            if (LOG.isTraceEnabled()) {
                LOG.trace("Janus-request returned: {}", restResponse.toString());
            }

            return restResponse;

        } catch (IOException e) {
            LOG.error("While doing Janus-request", e);
        }
        return null;

    }

    @Override
    public List<String> getAllowedSps(String idpentityid) {
        return getAllowedSps(idpentityid, null);
    }

    @Override
    public List<String> getAllowedSps(String idpentityid, String revision) {

        Assert.hasText(idpentityid, "idpentityid is a required parameter");
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put("idpentityid", idpentityid);
        if (!StringUtils.isBlank(revision)) {
            parameters.put("idprevision", revision);
        }

        URI signedUri;
        try {
            signedUri = sign("getAllowedSps", parameters);

            if (LOG.isTraceEnabled()) {
                LOG.trace("Signed Janus-request is: {}", signedUri);
            }

            @SuppressWarnings("unchecked")
            final List<String> restResponse = restTemplate.getForObject(signedUri, List.class);

            if (LOG.isTraceEnabled()) {
                LOG.trace("Janus-request returned: {}", restResponse.toString());
            }

            return restResponse;

        } catch (IOException e) {
            LOG.error("While doing Janus-request", e);
        }
        return null;
    }

    @Override
    public List<EntityMetadata> getSpList() {

        Map<String, String> parameters = new HashMap<String, String>();

        final Collection metadataAsStrings = CollectionUtils.collect(Arrays.asList(Metadata.values()),
                new Transformer() {
                    @Override
                    public Object transform(Object input) {
                        return ((Metadata) input).val();
                    }
                });

        parameters.put("keys", StringUtils.join(metadataAsStrings, ','));

        URI signedUri;
        try {
            signedUri = sign("getSpList", parameters);

            if (LOG.isTraceEnabled()) {
                LOG.trace("Signed Janus-request is: {}", signedUri);
            }

            @SuppressWarnings("unchecked")
            final Map<String, Map<String, Object>> restResponse = restTemplate.getForObject(signedUri, Map.class);

            if (LOG.isTraceEnabled()) {
                LOG.trace("Janus-request returned: {}", restResponse.toString());
            }

            List<EntityMetadata> entities = new ArrayList<EntityMetadata>();
            for (Map.Entry<String, Map<String, Object>> entry : restResponse.entrySet()) {
                String entityId = entry.getKey();
                final EntityMetadata e = EntityMetadata.fromMetadataMap(entry.getValue());
                e.setAppEntityId(entityId);
                entities.add(e);
            }

            return entities;

        } catch (IOException e) {
            LOG.error("While doing Janus-request", e);
        }
        return null;
    }

    @Override
    public List<EntityMetadata> getIdpList() {

        Map<String, String> parameters = new HashMap<String, String>();

        final Collection metadataAsStrings = CollectionUtils.collect(Arrays.asList(Metadata.values()),
                new Transformer() {
                    @Override
                    public Object transform(Object input) {
                        return ((Metadata) input).val();
                    }
                });

        parameters.put("keys", StringUtils.join(metadataAsStrings, ','));

        URI signedUri;
        try {
            signedUri = sign("getIdpList", parameters);

            if (LOG.isTraceEnabled()) {
                LOG.trace("Signed Janus-request is: {}", signedUri);
            }

            @SuppressWarnings("unchecked")
            final Map<String, Map<String, Object>> restResponse = restTemplate.getForObject(signedUri, Map.class);

            if (LOG.isTraceEnabled()) {
                LOG.trace("Janus-request returned: {}", restResponse.toString());
            }

            List<EntityMetadata> entities = new ArrayList<EntityMetadata>();
            for (Map.Entry<String, Map<String, Object>> entry : restResponse.entrySet()) {
                String entityId = entry.getKey();
                final EntityMetadata e = EntityMetadata.fromMetadataMap(entry.getValue());
                e.setAppEntityId(entityId);
                entities.add(e);
            }

            return entities;

        } catch (IOException e) {
            LOG.error("While doing Janus-request", e);
        }
        return null;
    }

    @Override
    public ARP getArp(String entityId) {
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put("entityid", entityId);
        URI signedUri = null;
        try {
            signedUri = sign("arp", parameters);
            if (LOG.isTraceEnabled()) {
                LOG.trace("Signed Janus-request is: {}", signedUri);
            }
        } catch (IOException e) {
            LOG.error("Could not do ARP request to Janus", e);
        }

        final Map restResponse = restTemplate.getForObject(signedUri, Map.class);
        if (LOG.isTraceEnabled()) {
            LOG.trace("Janus-request returned: {}", restResponse.toString());
        }

        return (restResponse == null) ? null : ARP.fromRestResponse(restResponse);
    }

    @Override
    public boolean isConnectionAllowed(String spEntityId, String idpEntityId) {
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put("spentityid", spEntityId);
        parameters.put("idpentityid", idpEntityId);
        URI signedUri = null;
        try {
            signedUri = sign("isConnectionAllowed", parameters);
            if (LOG.isTraceEnabled()) {
                LOG.trace("Signed Janus-request is: {}", signedUri);
            }
        } catch (IOException e) {
            LOG.error("Could not do isConnectionAllowed request to Janus", e);
        }

        final List restResponse = restTemplate.getForObject(signedUri, List.class);
        if (LOG.isTraceEnabled()) {
            LOG.trace("Janus-request returned: {}", restResponse.toString());
        }

        return CollectionUtils.isEmpty(restResponse) ? false : (Boolean) restResponse.get(0);
    }

    @Override
    public JanusEntity getEntity(String entityId) {
        Map<String, String> parameters = new HashMap<String, String>();
        parameters.put("entityid", entityId);
        URI signedUri = null;
        try {
            signedUri = sign("getEntity", parameters);
            if (LOG.isTraceEnabled()) {
                LOG.trace("Signed Janus-request is: {}", signedUri);
            }
        } catch (IOException e) {
            LOG.error("Could not do getEntity request to Janus", e);
        }

        @SuppressWarnings("unchecked")
        final Map<String, Object> restResponse = restTemplate.getForObject(signedUri, Map.class);

        if (LOG.isTraceEnabled()) {
            LOG.trace("Janus-request returned: {}", restResponse.toString());
        }

        return restResponse == null ? null : JanusEntity.fromJanusResponse(restResponse);
    }

    /**
     * Sign the given method call.
     * 
     * @param method
     *          the name of the method to call
     * @param parameters
     *          additional parameters that need to be passed to Janus
     * @return URI with parameters janus_sig and janus_key
     * @throws IOException
     */
    private URI sign(String method, Map<String, String> parameters) throws IOException {
        Map<String, String> keys = new TreeMap<String, String>();
        keys.put("janus_key", user);
        keys.put("method", method);

        keys.putAll(parameters);

        keys.put("rest", "1");
        keys.put("userid", user);
        Set<String> keySet = keys.keySet();
        StringBuilder toSign = new StringBuilder(secret);
        for (String key : keySet) {
            toSign.append(key);
            toSign.append(keys.get(key));
        }

        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("SHA-512");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Cannot use algorithm SHA-512", e);
        }
        digest.reset();
        final String charsetName = "UTF-8";
        byte[] input = digest.digest(toSign.toString().getBytes(charsetName));
        char[] value = Hex.encodeHex(input);
        String janus_sig = new String(value);
        keys.put("janus_sig", janus_sig);

        StringBuilder url = new StringBuilder();
        keySet = keys.keySet();
        for (String key : keySet) {
            if (url.length() > 0) {
                url.append('&');
            }
            url.append(key).append('=').append(URLEncoder.encode(keys.get(key), charsetName));
        }
        String uri = url.toString();
        return URI.create(janusUri + "?" + uri);
    }

    /**
     * @param restTemplate
     *          the restTemplate to set
     */
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    /**
     * @param janusUri
     *          the janusUri to set
     */
    public void setJanusUri(URI janusUri) {
        this.janusUri = janusUri;
    }

    /**
     * @param user
     *          the user to set
     */
    public void setUser(String user) {
        this.user = user;
    }

    /**
     * @param secret
     *          the secret to set
     */
    public void setSecret(String secret) {
        this.secret = secret;
    }
}