001/*
002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nelson Silva <nelson.silva@inevo.pt>
018 */
019package org.nuxeo.ecm.platform.auth.saml.binding;
020
021import org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder;
022import org.opensaml.common.binding.decoding.URIComparator;
023import org.opensaml.util.SimpleURLCanonicalizer;
024import org.opensaml.ws.message.MessageContext;
025import org.opensaml.ws.message.decoder.MessageDecoder;
026import org.opensaml.ws.message.decoder.MessageDecodingException;
027import org.opensaml.ws.message.encoder.MessageEncoder;
028import org.opensaml.ws.message.encoder.MessageEncodingException;
029import org.opensaml.ws.transport.InTransport;
030import org.opensaml.ws.transport.OutTransport;
031
032/**
033 * Based class for SAML bindings, used for parsing messages.
034 *
035 * @since 6.0
036 */
037public abstract class SAMLBinding {
038
039    protected MessageDecoder decoder;
040
041    protected MessageEncoder encoder;
042
043    /**
044     * URIComparator that strips scheme to avoid issues with reverse proxies
045     */
046    public static final URIComparator uriComparator = (uri1, uri2) -> {
047        if (uri1 == null && uri2 == null) {
048            return true;
049        } else if (uri1 == null || uri2 == null) {
050            return false;
051        } else {
052            String uri1Canon = SimpleURLCanonicalizer.canonicalize(uri1).replaceFirst("^(https:|http:)", "");
053            String uri2Canon = SimpleURLCanonicalizer.canonicalize(uri2).replaceFirst("^(https:|http:)", "");
054            return uri1Canon.equals(uri2Canon);
055        }
056    };
057
058    public SAMLBinding(MessageDecoder decoder, MessageEncoder encoder) {
059        this.decoder = decoder;
060        this.encoder = encoder;
061        // NXP-17044: strips scheme to fix validity check with reverse proxies
062        if (decoder != null) {
063            ((BaseSAMLMessageDecoder) decoder).setURIComparator(uriComparator);
064        }
065    }
066
067    /**
068     * Decodes the given message.
069     *
070     * @param context the message to decode
071     */
072    public void decode(MessageContext context) throws org.opensaml.xml.security.SecurityException,
073            MessageDecodingException {
074        decoder.decode(context);
075    }
076
077    /**
078     * Encodes the given message.
079     *
080     * @param context the message to encode
081     */
082    public void encode(MessageContext context) throws MessageEncodingException {
083        encoder.encode(context);
084    }
085
086    /**
087     * Returns the URI that identifies this binding.
088     *
089     * @return the URI
090     */
091    public abstract String getBindingURI();
092
093    /**
094     * Checks if this binding can be used to extract the message from the request.
095     *
096     * @return true if this binding supports the transport
097     */
098    public abstract boolean supports(InTransport transport);
099
100    /**
101     * Checks if this binding can use the given transport to send a message
102     *
103     * @return true if this binding supports the transport
104     */
105    public abstract boolean supports(OutTransport transport);
106}