AsRequestCreationHints.java

/*******************************************************************************
 * Copyright (c) 2019, RISE AB
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/
package se.sics.ace.rs;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.californium.core.coap.Request;

import com.upokecenter.cbor.CBORObject;
import com.upokecenter.cbor.CBORType;

import se.sics.ace.AceException;
import se.sics.ace.Constants;

/**
 * This class manages the creation of AS Request Creation Hints at the RS.
 * 
 * @author Ludwig Seitz and Marco Tiloca
 *
 */
public class AsRequestCreationHints {

    /**
     * Flag signaling whether to include the scope
     */
    private boolean includeScope;
    
    /**
     * The URI of the AS in charge of this RS
     */
    private String asUri;
    
    /**
     * The audience this RS identifies with, can be null
     */
    private String aud;
    
    /**
     * Flag signaling whether to create a client nonce
     */
    private boolean createNonce;
    

    /**
     * Constructor. Specifies which parameters are to be included in a AsRequestCreationHints
     * 
     * @param asUri  the required URI of the AS responsible for this RS
     * @param aud  the audience this RS identifies with or null if this parameter is to be omitted
     * @param includeScope  true if the scope is to be included  
     * @param createNonce  true if a nonce is to be created  
     */
    public AsRequestCreationHints(String asUri, 
            String aud, boolean includeScope, boolean createNonce) {
        if (asUri == null || asUri.isEmpty()) {
            throw new IllegalArgumentException(
                    "Cannot create an AsRequestCreationHints object "
                            + "with null or empty asUri field");
        }
        this.includeScope = includeScope;
        this.createNonce = createNonce;
        this.asUri = asUri;
        this.aud = aud;       
    }
    
    /**
     * Create the AS Request Creation Hints based on the configuration
     * of this class. 
     * 
     * Note: The token repository must have been initialized 
     * before calling this.
     * 
     * @param req  the client's request
     * @param kid  the kid linked to a the key used in the secure connection
     *  with the client, null if we don't have a secure connection
     *  
     * @return  the AS Request Creation Hints
     * @throws AceException   if the TokenRepository is not initialized
     * @throws InvalidKeyException  if the nonce creation fails
     * @throws NoSuchAlgorithmException  if the nonce creation fails
     */
    public CBORObject getHints(Request req, String kid) 
            throws InvalidKeyException, NoSuchAlgorithmException, AceException {
        CBORObject cbor = CBORObject.NewMap();
        cbor.Add(Constants.AS, this.asUri);          
        if (kid != null) {
        	if (kid != null) {
	            byte[] kidB = Base64.getDecoder().decode(kid);
	            cbor.Add(Constants.KID, kidB);
        	}
        }
        if (this.includeScope) {
            if (req == null) {
                throw new IllegalArgumentException("Request"
                        + " must both be non-null for scope creation");
            }

            
            String resource = req.getOptions().getUriPathString();
            short action = (short) req.getCode().value;  
            
            if (TokenRepository.getInstance() == null) {
                throw new AceException("TokenRepository not initialized");
            }
            CBORObject scope = TokenRepository.getInstance().getScope(resource, action);
            
            cbor.Add(Constants.SCOPE, scope);   
        }  
        if (this.aud != null) {
            cbor.Add(Constants.AUDIENCE, this.aud);
        }        
       
        if (this.createNonce) {
            byte[] cnonce = CnonceHandler.getInstance().createNonce();
            cbor.Add(Constants.CNONCE, cnonce);
        }        
        return cbor;
    }

    /**
     * Parse a CBOR object containing AS Request Creation Hints to a Map.
     * 
     * @param hints  the CBOR object, must be a CBOR Map containing at least
     * the AS parameter.
     * 
     * @return  a Map of the hints
     */
    public static Map<Short, CBORObject> parseHints(CBORObject hints) {
        if (!hints.getType().equals(CBORType.Map)) {
            throw new IllegalArgumentException("AS Request Creation Hints must"
                    + "be a CBOR map");
        }
        Map<Short, CBORObject> h = new HashMap<>();
        if (!hints.ContainsKey(CBORObject.FromObject(Constants.AS))){
            throw new IllegalArgumentException("AS Request Creation Hints"
                    + "malformed, must contain AS parameter");
        }
        h.put(Constants.AS, hints.get(CBORObject.FromObject(Constants.AS)));
        if (hints.ContainsKey(CBORObject.FromObject(Constants.KID))) {
            h.put(Constants.KID, hints.get(
                    CBORObject.FromObject(Constants.KID)));
        }
        if (hints.ContainsKey(CBORObject.FromObject(Constants.SCOPE))) {
            h.put(Constants.SCOPE, hints.get(
                    CBORObject.FromObject(Constants.SCOPE)));
        }
        if (hints.ContainsKey(CBORObject.FromObject(Constants.AUDIENCE))) {
            h.put(Constants.AUDIENCE, hints.get(
                    CBORObject.FromObject(Constants.AUDIENCE)));
        }
        if (hints.ContainsKey(CBORObject.FromObject(Constants.CNONCE))) {
            h.put(Constants.CNONCE, hints.get(
                    CBORObject.FromObject(Constants.CNONCE)));
        }
        return h;
    }

}