org.adeptnet.atlassian.common.Common.java Source code

Java tutorial

Introduction

Here is the source code for org.adeptnet.atlassian.common.Common.java

Source

/*
 * Copyright 2015 Francois Steyn - Adept Internet (PTY) LTD (francois.s@adept.co.za).
 *
 * 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 org.adeptnet.atlassian.common;

import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.adeptnet.auth.kerberos.Krb5;
import org.adeptnet.auth.kerberos.Krb5ConfigImpl;
import org.adeptnet.auth.saml.AttributeSet;
import org.adeptnet.auth.saml.SAMLClient;
import org.adeptnet.auth.saml.SAMLConfigImpl;
import org.adeptnet.auth.saml.SAMLException;
import org.adeptnet.auth.saml.SAMLInit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opensaml.ws.message.encoder.MessageEncodingException;

/**
 *
 * @author Francois Steyn - Adept Internet (PTY) LTD (francois.s@adept.co.za)
 */
public class Common {

    private static final Log LOG = LogFactory.getLog(Common.class);

    private final static String KRB5_ENABLE = "krb5-enable";
    private final static String KRB5_SKIP401 = "krb5-skip401";
    private final static String KRB5_REALM = "krb5-realm";
    private final static String KRB5_KEYTAB = "krb5-keytab";
    private final static String KRB5_LOGIN_CONTEXT = "krb5-login-context";
    private final static String SAML_ENABLE = "saml-enable";
    private final static String SAML_IDP_CONFIG = "saml-idp-config";
    private final static String SAML_SP_CONFIG = "saml-sp-config";
    private final static String SAML_KEYSTORE_NAME = "saml-keystore-name";
    private final static String SAML_KEYSTORE_PASSWORD = "saml-keystore-password";
    private final static String SAML_CERTIFICATE_ALIAS = "saml-certificate-alias";

    private final Krb5ConfigImpl krb5Cfg = new Krb5ConfigImpl();

    private SAMLClient samlClient;
    private final SAMLConfigImpl samlCfg = new SAMLConfigImpl();
    private final List<Pattern> patterns = new ArrayList<>();

    private boolean hasInit;

    private boolean krb5Enabled;
    private boolean samlEnabled;

    public Common() {
    }

    public Common check() throws IllegalStateException {
        if (!hasInit) {
            throw new IllegalStateException("Please INIT before use");
        }
        return this;
    }

    private void initSkip401(final Map<String, String> params) {
        if (!params.containsKey(KRB5_SKIP401)) {
            return;
        }
        final String[] skips = params.get(KRB5_SKIP401).split("\n");
        for (final String _skip : skips) {
            final String skip = _skip.trim();
            if (skip.isEmpty()) {
                continue;
            }
            try {
                final Pattern pattern = Pattern.compile(skip);
                patterns.add(pattern);
            } catch (PatternSyntaxException ex) {
                LOG.error(String.format("skip401: %s - %s", skip, ex.getMessage()), ex);
            }
        }
    }

    public void init(final Map<String, String> params) {
        krb5Enabled = Boolean.valueOf(params.get(KRB5_ENABLE));
        initSkip401(params);
        krb5Cfg.setRealm(params.get(KRB5_REALM));
        if (params.containsKey(KRB5_KEYTAB)) {
            krb5Cfg.setKeytabName(params.get(KRB5_KEYTAB));
        }
        if (params.containsKey(KRB5_LOGIN_CONTEXT)) {
            krb5Cfg.setContextName(params.get(KRB5_LOGIN_CONTEXT));
        }

        samlEnabled = Boolean.valueOf(params.get(SAML_ENABLE));
        samlCfg.setIdpConfigName(params.get(SAML_IDP_CONFIG));
        samlCfg.setSpConfigName(params.get(SAML_SP_CONFIG));
        samlCfg.setKeystoreName(params.get(SAML_KEYSTORE_NAME));
        samlCfg.setKeystorePassword(params.get(SAML_KEYSTORE_PASSWORD));
        samlCfg.setCertificateAlias(params.get(SAML_CERTIFICATE_ALIAS));
        if (LOG.isDebugEnabled()) {
            LOG.debug(params);
            LOG.debug(String.format("krb5Enabled: %s", krb5Enabled));
            LOG.debug(String.format("samlEnabled: %s", samlEnabled));
        }

        hasInit = true;
    }

    private SAMLClient getSAMLClient(final ServletContext servletContext) throws SAMLException {
        if (samlClient == null) {
            samlCfg.init(getFileName(servletContext));
            samlClient = new SAMLClient(samlCfg);
        }
        return samlClient;
    }

    public void doSAMLRedirect(final HttpServletRequest request, final HttpServletResponse response,
            final String relayState) throws SAMLException, MessageEncodingException {
        if (!samlEnabled) {
            throw new SAMLException("SAML is not enabled");
        }

        final SAMLClient client = getSAMLClient(request.getServletContext());
        client.doSAMLRedirect(response, relayState);
    }

    private Function<String, String> getFileName(final ServletContext servletContext) {
        return (fileName) -> {
            return servletContext.getRealPath(fileName);
        };
    }

    public String getKrb5UserName(final HttpServletRequest request) {
        if (!krb5Enabled) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("!krb5Enabled");
            }
            return null;
        }
        final String _ticket = request.getHeader(Krb5.AUTHORIZATION);
        if (_ticket == null) {
            return null;
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("Found Kerberos Ticket");
        }
        if (LOG.isTraceEnabled()) {
            LOG.trace(_ticket);
        }

        final String ticket = Krb5.extractTicket(_ticket);
        if (ticket == null) {
            return null;
        }

        final String serverName = Krb5.resolveServerName(request.getServerName());

        krb5Cfg.init(getFileName(request.getServletContext()));
        final String realm = String.format("@%s", krb5Cfg.getRealm());
        final String spn = String.format("HTTP/%s%s", serverName, realm);
        if (LOG.isDebugEnabled()) {
            LOG.debug(String.format("SPN: %s", spn));
        }
        final String username = new Krb5(krb5Cfg).isTicketValid(spn, Base64.getDecoder().decode(ticket));

        if (username == null || !username.endsWith(realm)) {
            LOG.error(String.format("Invalid username: %s", username));
            return null;
        }

        return username.split("@")[0];
    }

    public String getSAMLUserName(final HttpServletRequest request) {
        if (!samlEnabled) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("!samlEnabled");
            }
            return null;
        }
        final String samlTicket = request.getParameter(SAMLClient.SAML_RESPONSE);
        if (samlTicket == null) {
            return null;
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Found SAML Ticket");
        }
        if (LOG.isTraceEnabled()) {
            LOG.trace(samlTicket);
        }
        final AttributeSet aset;
        try {
            final SAMLClient client = getSAMLClient(request.getServletContext());
            if ("GET".equalsIgnoreCase(request.getMethod())) {
                aset = client.validateResponseGET(request.getQueryString());
            } else {
                aset = client.validateResponsePOST(samlTicket);
            }
        } catch (SAMLException ex) {
            LOG.fatal(ex.getMessage(), ex);
            return null;
        }
        return aset.getNameId();
    }

    public boolean krb5Skip401(final String uri) {
        if (LOG.isTraceEnabled()) {
            LOG.trace(String.format("krb5Skip401: %s", uri));
        }
        for (final Pattern pattern : patterns) {
            if (pattern.matcher(uri).matches()) {
                return true;
            }
        }
        return false;
    }

    public boolean isKrb5Enabled() {
        return krb5Enabled;
    }

    public boolean isSamlEnabled() {
        return samlEnabled;
    }

}