Search in sources :

Example 81 with SSLPeerUnverifiedException

use of javax.net.ssl.SSLPeerUnverifiedException in project nifi by apache.

the class PostHTTP method onTrigger.

@Override
public void onTrigger(final ProcessContext context, final ProcessSession session) {
    FlowFile firstFlowFile = session.get();
    if (firstFlowFile == null) {
        return;
    }
    final ComponentLog logger = getLogger();
    final String url = context.getProperty(URL).evaluateAttributeExpressions(firstFlowFile).getValue();
    try {
        new java.net.URL(url);
    } catch (final MalformedURLException e) {
        logger.error("After substituting attribute values for {}, URL is {}; this is not a valid URL, so routing to failure", new Object[] { firstFlowFile, url });
        firstFlowFile = session.penalize(firstFlowFile);
        session.transfer(firstFlowFile, REL_FAILURE);
        return;
    }
    final List<FlowFile> toSend = new ArrayList<>();
    toSend.add(firstFlowFile);
    final boolean sendAsFlowFile = context.getProperty(SEND_AS_FLOWFILE).asBoolean();
    final int compressionLevel = context.getProperty(COMPRESSION_LEVEL).asInteger();
    final String userAgent = context.getProperty(USER_AGENT).getValue();
    final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
    requestConfigBuilder.setConnectionRequestTimeout(context.getProperty(DATA_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
    requestConfigBuilder.setConnectTimeout(context.getProperty(CONNECTION_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
    requestConfigBuilder.setRedirectsEnabled(false);
    requestConfigBuilder.setSocketTimeout(context.getProperty(DATA_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
    final RequestConfig requestConfig = requestConfigBuilder.build();
    final StreamThrottler throttler = throttlerRef.get();
    final Double maxBatchBytes = context.getProperty(MAX_BATCH_SIZE).asDataSize(DataUnit.B);
    final AtomicLong bytesToSend = new AtomicLong(firstFlowFile.getSize());
    DestinationAccepts destinationAccepts = null;
    CloseableHttpClient client = null;
    final String transactionId = UUID.randomUUID().toString();
    final AtomicReference<String> dnHolder = new AtomicReference<>("none");
    final Config config = getConfig(url, context);
    final HttpClientConnectionManager conMan = config.getConnectionManager();
    final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
    clientBuilder.setConnectionManager(conMan);
    clientBuilder.setUserAgent(userAgent);
    clientBuilder.addInterceptorFirst(new HttpResponseInterceptor() {

        @Override
        public void process(final HttpResponse response, final HttpContext httpContext) throws HttpException, IOException {
            final HttpCoreContext coreContext = HttpCoreContext.adapt(httpContext);
            final ManagedHttpClientConnection conn = coreContext.getConnection(ManagedHttpClientConnection.class);
            if (!conn.isOpen()) {
                return;
            }
            final SSLSession sslSession = conn.getSSLSession();
            if (sslSession != null) {
                final Certificate[] certChain = sslSession.getPeerCertificates();
                if (certChain == null || certChain.length == 0) {
                    throw new SSLPeerUnverifiedException("No certificates found");
                }
                try {
                    final X509Certificate cert = CertificateUtils.convertAbstractX509Certificate(certChain[0]);
                    dnHolder.set(cert.getSubjectDN().getName().trim());
                } catch (CertificateException e) {
                    final String msg = "Could not extract subject DN from SSL session peer certificate";
                    logger.warn(msg);
                    throw new SSLPeerUnverifiedException(msg);
                }
            }
        }
    });
    clientBuilder.disableAutomaticRetries();
    clientBuilder.disableContentCompression();
    final String username = context.getProperty(USERNAME).getValue();
    final String password = context.getProperty(PASSWORD).getValue();
    // set the credentials if appropriate
    if (username != null) {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        if (password == null) {
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username));
        } else {
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
        }
        clientBuilder.setDefaultCredentialsProvider(credentialsProvider);
    }
    // Set the proxy if specified
    if (context.getProperty(PROXY_HOST).isSet() && context.getProperty(PROXY_PORT).isSet()) {
        final String host = context.getProperty(PROXY_HOST).getValue();
        final int port = context.getProperty(PROXY_PORT).asInteger();
        clientBuilder.setProxy(new HttpHost(host, port));
    }
    client = clientBuilder.build();
    // determine whether or not destination accepts flowfile/gzip
    destinationAccepts = config.getDestinationAccepts();
    if (destinationAccepts == null) {
        try {
            destinationAccepts = getDestinationAcceptance(sendAsFlowFile, client, url, getLogger(), transactionId);
            config.setDestinationAccepts(destinationAccepts);
        } catch (final IOException e) {
            firstFlowFile = session.penalize(firstFlowFile);
            session.transfer(firstFlowFile, REL_FAILURE);
            logger.error("Unable to communicate with destination {} to determine whether or not it can accept " + "flowfiles/gzip; routing {} to failure due to {}", new Object[] { url, firstFlowFile, e });
            context.yield();
            return;
        }
    }
    // then we can get more flowfiles from the session up to MAX_BATCH_SIZE for the same URL
    if (sendAsFlowFile && (destinationAccepts.isFlowFileV3Accepted() || destinationAccepts.isFlowFileV2Accepted())) {
        toSend.addAll(session.get(new FlowFileFilter() {

            @Override
            public FlowFileFilterResult filter(FlowFile flowFile) {
                // if over MAX_BATCH_SIZE, then stop adding files
                if (bytesToSend.get() + flowFile.getSize() > maxBatchBytes) {
                    return FlowFileFilterResult.REJECT_AND_TERMINATE;
                }
                // check URL to see if this flowfile can be included in the batch
                final String urlToCheck = context.getProperty(URL).evaluateAttributeExpressions(flowFile).getValue();
                if (url.equals(urlToCheck)) {
                    bytesToSend.addAndGet(flowFile.getSize());
                    return FlowFileFilterResult.ACCEPT_AND_CONTINUE;
                } else {
                    return FlowFileFilterResult.REJECT_AND_CONTINUE;
                }
            }
        }));
    }
    final HttpPost post = new HttpPost(url);
    final DestinationAccepts accepts = destinationAccepts;
    final boolean isDestinationLegacyNiFi = accepts.getProtocolVersion() == null;
    final EntityTemplate entity = new EntityTemplate(new ContentProducer() {

        @Override
        public void writeTo(final OutputStream rawOut) throws IOException {
            final OutputStream throttled = throttler == null ? rawOut : throttler.newThrottledOutputStream(rawOut);
            OutputStream wrappedOut = new BufferedOutputStream(throttled);
            if (compressionLevel > 0 && accepts.isGzipAccepted()) {
                wrappedOut = new GZIPOutputStream(wrappedOut, compressionLevel);
            }
            try (final OutputStream out = wrappedOut) {
                for (final FlowFile flowFile : toSend) {
                    session.read(flowFile, new InputStreamCallback() {

                        @Override
                        public void process(final InputStream rawIn) throws IOException {
                            try (final InputStream in = new BufferedInputStream(rawIn)) {
                                FlowFilePackager packager = null;
                                if (!sendAsFlowFile) {
                                    packager = null;
                                } else if (accepts.isFlowFileV3Accepted()) {
                                    packager = new FlowFilePackagerV3();
                                } else if (accepts.isFlowFileV2Accepted()) {
                                    packager = new FlowFilePackagerV2();
                                } else if (accepts.isFlowFileV1Accepted()) {
                                    packager = new FlowFilePackagerV1();
                                }
                                // formats is acceptable if sending as FlowFile.
                                if (packager == null) {
                                    StreamUtils.copy(in, out);
                                } else {
                                    final Map<String, String> flowFileAttributes;
                                    if (isDestinationLegacyNiFi) {
                                        // Old versions of NiFi expect nf.file.name and nf.file.path to indicate filename & path;
                                        // in order to maintain backward compatibility, we copy the filename & path to those attribute keys.
                                        flowFileAttributes = new HashMap<>(flowFile.getAttributes());
                                        flowFileAttributes.put("nf.file.name", flowFile.getAttribute(CoreAttributes.FILENAME.key()));
                                        flowFileAttributes.put("nf.file.path", flowFile.getAttribute(CoreAttributes.PATH.key()));
                                    } else {
                                        flowFileAttributes = flowFile.getAttributes();
                                    }
                                    packager.packageFlowFile(in, out, flowFileAttributes, flowFile.getSize());
                                }
                            }
                        }
                    });
                }
                out.flush();
            }
        }
    }) {

        @Override
        public long getContentLength() {
            if (compressionLevel == 0 && !sendAsFlowFile && !context.getProperty(CHUNKED_ENCODING).asBoolean()) {
                return toSend.get(0).getSize();
            } else {
                return -1;
            }
        }
    };
    if (context.getProperty(CHUNKED_ENCODING).isSet()) {
        entity.setChunked(context.getProperty(CHUNKED_ENCODING).asBoolean());
    }
    post.setEntity(entity);
    post.setConfig(requestConfig);
    final String contentType;
    if (sendAsFlowFile) {
        if (accepts.isFlowFileV3Accepted()) {
            contentType = APPLICATION_FLOW_FILE_V3;
        } else if (accepts.isFlowFileV2Accepted()) {
            contentType = APPLICATION_FLOW_FILE_V2;
        } else if (accepts.isFlowFileV1Accepted()) {
            contentType = APPLICATION_FLOW_FILE_V1;
        } else {
            logger.error("Cannot send data to {} because the destination does not accept FlowFiles and this processor is " + "configured to deliver FlowFiles; rolling back session", new Object[] { url });
            session.rollback();
            context.yield();
            IOUtils.closeQuietly(client);
            return;
        }
    } else {
        final String contentTypeValue = context.getProperty(CONTENT_TYPE).evaluateAttributeExpressions(toSend.get(0)).getValue();
        contentType = StringUtils.isBlank(contentTypeValue) ? DEFAULT_CONTENT_TYPE : contentTypeValue;
    }
    final String attributeHeaderRegex = context.getProperty(ATTRIBUTES_AS_HEADERS_REGEX).getValue();
    if (attributeHeaderRegex != null && !sendAsFlowFile && toSend.size() == 1) {
        final Pattern pattern = Pattern.compile(attributeHeaderRegex);
        final Map<String, String> attributes = toSend.get(0).getAttributes();
        for (final Map.Entry<String, String> entry : attributes.entrySet()) {
            final String key = entry.getKey();
            if (pattern.matcher(key).matches()) {
                post.setHeader(entry.getKey(), entry.getValue());
            }
        }
    }
    post.setHeader(CONTENT_TYPE_HEADER, contentType);
    post.setHeader(FLOWFILE_CONFIRMATION_HEADER, "true");
    post.setHeader(PROTOCOL_VERSION_HEADER, PROTOCOL_VERSION);
    post.setHeader(TRANSACTION_ID_HEADER, transactionId);
    if (compressionLevel > 0 && accepts.isGzipAccepted()) {
        if (sendAsFlowFile) {
            post.setHeader(GZIPPED_HEADER, "true");
        } else {
            post.setHeader(CONTENT_ENCODING_HEADER, CONTENT_ENCODING_GZIP_VALUE);
        }
    }
    // Do the actual POST
    final String flowFileDescription = toSend.size() <= 10 ? toSend.toString() : toSend.size() + " FlowFiles";
    final String uploadDataRate;
    final long uploadMillis;
    CloseableHttpResponse response = null;
    try {
        final StopWatch stopWatch = new StopWatch(true);
        response = client.execute(post);
        // consume input stream entirely, ignoring its contents. If we
        // don't do this, the Connection will not be returned to the pool
        EntityUtils.consume(response.getEntity());
        stopWatch.stop();
        uploadDataRate = stopWatch.calculateDataRate(bytesToSend.get());
        uploadMillis = stopWatch.getDuration(TimeUnit.MILLISECONDS);
    } catch (final IOException e) {
        logger.error("Failed to Post {} due to {}; transferring to failure", new Object[] { flowFileDescription, e });
        context.yield();
        for (FlowFile flowFile : toSend) {
            flowFile = session.penalize(flowFile);
            session.transfer(flowFile, REL_FAILURE);
        }
        return;
    } finally {
        if (response != null) {
            try {
                response.close();
            } catch (final IOException e) {
                getLogger().warn("Failed to close HTTP Response due to {}", new Object[] { e });
            }
        }
    }
    // If we get a 'SEE OTHER' status code and an HTTP header that indicates that the intent
    // of the Location URI is a flowfile hold, we will store this holdUri. This prevents us
    // from posting to some other webservice and then attempting to delete some resource to which
    // we are redirected
    final int responseCode = response.getStatusLine().getStatusCode();
    final String responseReason = response.getStatusLine().getReasonPhrase();
    String holdUri = null;
    if (responseCode == HttpServletResponse.SC_SEE_OTHER) {
        final Header locationUriHeader = response.getFirstHeader(LOCATION_URI_INTENT_NAME);
        if (locationUriHeader != null) {
            if (LOCATION_URI_INTENT_VALUE.equals(locationUriHeader.getValue())) {
                final Header holdUriHeader = response.getFirstHeader(LOCATION_HEADER_NAME);
                if (holdUriHeader != null) {
                    holdUri = holdUriHeader.getValue();
                }
            }
        }
        if (holdUri == null) {
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                logger.error("Failed to Post {} to {}: sent content and received status code {}:{} but no Hold URI", new Object[] { flowFile, url, responseCode, responseReason });
                session.transfer(flowFile, REL_FAILURE);
            }
            return;
        }
    }
    if (holdUri == null) {
        if (responseCode == HttpServletResponse.SC_SERVICE_UNAVAILABLE) {
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                logger.error("Failed to Post {} to {}: response code was {}:{}; will yield processing, " + "since the destination is temporarily unavailable", new Object[] { flowFile, url, responseCode, responseReason });
                session.transfer(flowFile, REL_FAILURE);
            }
            context.yield();
            return;
        }
        if (responseCode >= 300) {
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                logger.error("Failed to Post {} to {}: response code was {}:{}", new Object[] { flowFile, url, responseCode, responseReason });
                session.transfer(flowFile, REL_FAILURE);
            }
            return;
        }
        logger.info("Successfully Posted {} to {} in {} at a rate of {}", new Object[] { flowFileDescription, url, FormatUtils.formatMinutesSeconds(uploadMillis, TimeUnit.MILLISECONDS), uploadDataRate });
        for (final FlowFile flowFile : toSend) {
            session.getProvenanceReporter().send(flowFile, url, "Remote DN=" + dnHolder.get(), uploadMillis, true);
            session.transfer(flowFile, REL_SUCCESS);
        }
        return;
    }
    // 
    // the response indicated a Hold URI; delete the Hold.
    // 
    // determine the full URI of the Flow File's Hold; Unfortunately, the responses that are returned have
    // changed over the past, so we have to take into account a few different possibilities.
    String fullHoldUri = holdUri;
    if (holdUri.startsWith("/contentListener")) {
        // If the Hold URI that we get starts with /contentListener, it may not really be /contentListener,
        // as this really indicates that it should be whatever we posted to -- if posting directly to the
        // ListenHTTP component, it will be /contentListener, but if posting to a proxy/load balancer, we may
        // be posting to some other URL.
        fullHoldUri = url + holdUri.substring(16);
    } else if (holdUri.startsWith("/")) {
        // URL indicates the full path but not hostname or port; use the same hostname & port that we posted
        // to but use the full path indicated by the response.
        int firstSlash = url.indexOf("/", 8);
        if (firstSlash < 0) {
            firstSlash = url.length();
        }
        final String beforeSlash = url.substring(0, firstSlash);
        fullHoldUri = beforeSlash + holdUri;
    } else if (!holdUri.startsWith("http")) {
        // Absolute URL
        fullHoldUri = url + (url.endsWith("/") ? "" : "/") + holdUri;
    }
    final HttpDelete delete = new HttpDelete(fullHoldUri);
    delete.setHeader(TRANSACTION_ID_HEADER, transactionId);
    while (true) {
        try {
            final HttpResponse holdResponse = client.execute(delete);
            EntityUtils.consume(holdResponse.getEntity());
            final int holdStatusCode = holdResponse.getStatusLine().getStatusCode();
            final String holdReason = holdResponse.getStatusLine().getReasonPhrase();
            if (holdStatusCode >= 300) {
                logger.error("Failed to delete Hold that destination placed on {}: got response code {}:{}; routing to failure", new Object[] { flowFileDescription, holdStatusCode, holdReason });
                for (FlowFile flowFile : toSend) {
                    flowFile = session.penalize(flowFile);
                    session.transfer(flowFile, REL_FAILURE);
                }
                return;
            }
            logger.info("Successfully Posted {} to {} in {} milliseconds at a rate of {}", new Object[] { flowFileDescription, url, uploadMillis, uploadDataRate });
            for (final FlowFile flowFile : toSend) {
                session.getProvenanceReporter().send(flowFile, url);
                session.transfer(flowFile, REL_SUCCESS);
            }
            return;
        } catch (final IOException e) {
            logger.warn("Failed to delete Hold that destination placed on {} due to {}", new Object[] { flowFileDescription, e });
        }
        if (!isScheduled()) {
            context.yield();
            logger.warn("Failed to delete Hold that destination placed on {}; Processor has been stopped so routing FlowFile(s) to failure", new Object[] { flowFileDescription });
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                session.transfer(flowFile, REL_FAILURE);
            }
            return;
        }
    }
}
Also used : HttpPost(org.apache.http.client.methods.HttpPost) MalformedURLException(java.net.MalformedURLException) BasicCredentialsProvider(org.apache.http.impl.client.BasicCredentialsProvider) GZIPOutputStream(org.apache.nifi.stream.io.GZIPOutputStream) BufferedOutputStream(java.io.BufferedOutputStream) OutputStream(java.io.OutputStream) ArrayList(java.util.ArrayList) EntityTemplate(org.apache.http.entity.EntityTemplate) CertificateException(java.security.cert.CertificateException) FlowFilePackager(org.apache.nifi.util.FlowFilePackager) GZIPOutputStream(org.apache.nifi.stream.io.GZIPOutputStream) BufferedInputStream(java.io.BufferedInputStream) HttpHost(org.apache.http.HttpHost) CloseableHttpResponse(org.apache.http.client.methods.CloseableHttpResponse) HttpClientConnectionManager(org.apache.http.conn.HttpClientConnectionManager) PoolingHttpClientConnectionManager(org.apache.http.impl.conn.PoolingHttpClientConnectionManager) FlowFile(org.apache.nifi.flowfile.FlowFile) RequestConfig(org.apache.http.client.config.RequestConfig) FlowFileFilter(org.apache.nifi.processor.FlowFileFilter) ComponentLog(org.apache.nifi.logging.ComponentLog) X509Certificate(java.security.cert.X509Certificate) UsernamePasswordCredentials(org.apache.http.auth.UsernamePasswordCredentials) Header(org.apache.http.Header) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) LeakyBucketStreamThrottler(org.apache.nifi.stream.io.LeakyBucketStreamThrottler) StreamThrottler(org.apache.nifi.stream.io.StreamThrottler) ContentProducer(org.apache.http.entity.ContentProducer) HttpDelete(org.apache.http.client.methods.HttpDelete) RequestConfig(org.apache.http.client.config.RequestConfig) HttpClientBuilder(org.apache.http.impl.client.HttpClientBuilder) HttpException(org.apache.http.HttpException) BufferedOutputStream(java.io.BufferedOutputStream) CloseableHttpClient(org.apache.http.impl.client.CloseableHttpClient) Pattern(java.util.regex.Pattern) BufferedInputStream(java.io.BufferedInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) SSLPeerUnverifiedException(javax.net.ssl.SSLPeerUnverifiedException) HttpContext(org.apache.http.protocol.HttpContext) SSLSession(javax.net.ssl.SSLSession) HttpResponse(org.apache.http.HttpResponse) CloseableHttpResponse(org.apache.http.client.methods.CloseableHttpResponse) AtomicReference(java.util.concurrent.atomic.AtomicReference) IOException(java.io.IOException) CredentialsProvider(org.apache.http.client.CredentialsProvider) BasicCredentialsProvider(org.apache.http.impl.client.BasicCredentialsProvider) StopWatch(org.apache.nifi.util.StopWatch) ManagedHttpClientConnection(org.apache.http.conn.ManagedHttpClientConnection) AtomicLong(java.util.concurrent.atomic.AtomicLong) HttpCoreContext(org.apache.http.protocol.HttpCoreContext) HttpResponseInterceptor(org.apache.http.HttpResponseInterceptor) InputStreamCallback(org.apache.nifi.processor.io.InputStreamCallback) FlowFilePackagerV3(org.apache.nifi.util.FlowFilePackagerV3) FlowFilePackagerV2(org.apache.nifi.util.FlowFilePackagerV2) FlowFilePackagerV1(org.apache.nifi.util.FlowFilePackagerV1)

Example 82 with SSLPeerUnverifiedException

use of javax.net.ssl.SSLPeerUnverifiedException in project nifi by apache.

the class FlowFileIngestServiceInterceptor method interceptCall.

/**
 * Intercept incoming and outgoing messages and enforce any necessary controls
 *
 * @param call the request message
 * @param headers the request metadata
 * @param next the next interceptor in the interceptor chain prior to the service implementation
 * @param <I> The message request type (e.g. ReqT)
 * @param <O> The message reply type (e.g. RespT)
 *
 * @return a listener for the incoming call.
 */
@Override
public <I, O> ServerCall.Listener<I> interceptCall(final ServerCall<I, O> call, final Metadata headers, final ServerCallHandler<I, O> next) {
    final Attributes attributes = call.getAttributes();
    final SocketAddress socketAddress = attributes.get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
    final String clientIp = clientIp(socketAddress);
    String foundSubject = DEFAULT_FOUND_SUBJECT;
    // enforce that the DN on the client cert matches the configured pattern
    final SSLSession sslSession = attributes.get(Grpc.TRANSPORT_ATTR_SSL_SESSION);
    if (this.authorizedDNpattern != null && sslSession != null) {
        try {
            final X509Certificate[] certs = sslSession.getPeerCertificateChain();
            if (certs != null && certs.length > 0) {
                for (final X509Certificate cert : certs) {
                    foundSubject = cert.getSubjectDN().getName();
                    if (authorizedDNpattern.matcher(foundSubject).matches()) {
                        break;
                    } else {
                        logger.warn("Rejecting transfer attempt from " + foundSubject + " because the DN is not authorized, host=" + clientIp);
                        call.close(Status.PERMISSION_DENIED.withDescription(DN_UNAUTHORIZED + foundSubject), headers);
                        return IDENTITY_LISTENER;
                    }
                }
            }
        } catch (final SSLPeerUnverifiedException e) {
            logger.debug("skipping DN authorization for request from {}.", new Object[] { clientIp }, e);
        }
    }
    // contextualize the DN and IP for use in the RPC implementation
    final Context context = Context.current().withValue(REMOTE_HOST_KEY, clientIp).withValue(REMOTE_DN_KEY, foundSubject);
    // if we got to this point, there were no errors, call the next interceptor in the chain
    return Contexts.interceptCall(context, call, headers, next);
}
Also used : Context(io.grpc.Context) SSLPeerUnverifiedException(javax.net.ssl.SSLPeerUnverifiedException) Attributes(io.grpc.Attributes) SSLSession(javax.net.ssl.SSLSession) SocketAddress(java.net.SocketAddress) InetSocketAddress(java.net.InetSocketAddress) X509Certificate(javax.security.cert.X509Certificate)

Example 83 with SSLPeerUnverifiedException

use of javax.net.ssl.SSLPeerUnverifiedException in project iaf by ibissource.

the class AuthSSLProtocolSocketFactoryBase method verifyHostname.

/**
 * Describe <code>verifyHostname</code> method here.
 *
 * @param socket a <code>SSLSocket</code> value
 * @exception SSLPeerUnverifiedException  If there are problems obtaining
 * the server certificates from the SSL session, or the server host name
 * does not match with the "Common Name" in the server certificates
 * SubjectDN.
 * @exception UnknownHostException  If we are not able to resolve
 * the SSL sessions returned server host name.
 */
protected void verifyHostname(SSLSocket socket) throws SSLPeerUnverifiedException, UnknownHostException {
    if (!verifyHostname)
        return;
    SSLSession session = socket.getSession();
    if (session == null) {
        throw new UnknownHostException("could not obtain session from socket");
    }
    String hostname = session.getPeerHost();
    try {
        InetAddress.getByName(hostname);
    } catch (UnknownHostException uhe) {
        String msg = "Could not resolve SSL sessions server hostname: " + hostname;
        // Under WebSphere, hostname can be equal to proxy-hostname
        log.warn(msg, uhe);
    // throw new UnknownHostException(msg);
    }
    javax.security.cert.X509Certificate[] certs = session.getPeerCertificateChain();
    if (certs == null || certs.length == 0)
        throw new SSLPeerUnverifiedException("No server certificates found!");
    // get the servers DN in its string representation
    String dn = certs[0].getSubjectDN().getName();
    // server, in case one has to debug a problem with the installed certs.
    if (log.isInfoEnabled()) {
        log.info("Server certificate chain:");
        for (int i = 0; i < certs.length; i++) {
            log.info("X509Certificate[" + i + "]=" + certs[i]);
        }
    }
    // get the common name from the first cert
    String cn = getCN(dn);
    if (hostname.equalsIgnoreCase(cn)) {
        if (log.isInfoEnabled()) {
            log.info("Target hostname valid: " + cn);
        }
    } else {
        throw new SSLPeerUnverifiedException("HTTPS hostname invalid: expected '" + hostname + "', received '" + cn + "'");
    }
}
Also used : UnknownHostException(java.net.UnknownHostException) SSLPeerUnverifiedException(javax.net.ssl.SSLPeerUnverifiedException) SSLSession(javax.net.ssl.SSLSession) X509Certificate(java.security.cert.X509Certificate)

Example 84 with SSLPeerUnverifiedException

use of javax.net.ssl.SSLPeerUnverifiedException in project camel by apache.

the class NettyEndpoint method enrichWithClientCertInformation.

/**
     * Enriches the message with client certificate details such as subject name, serial number etc.
     * <p/>
     * If the certificate is unverified then the headers is not enriched.
     *
     * @param sslSession  the SSL session
     * @param message     the message to enrich
     */
protected void enrichWithClientCertInformation(SSLSession sslSession, Message message) {
    try {
        X509Certificate[] certificates = sslSession.getPeerCertificateChain();
        if (certificates != null && certificates.length > 0) {
            X509Certificate cert = certificates[0];
            Principal subject = cert.getSubjectDN();
            if (subject != null) {
                message.setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_SUBJECT_NAME, subject.getName());
            }
            Principal issuer = cert.getIssuerDN();
            if (issuer != null) {
                message.setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_ISSUER_NAME, issuer.getName());
            }
            BigInteger serial = cert.getSerialNumber();
            if (serial != null) {
                message.setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_SERIAL_NO, serial.toString());
            }
            message.setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_NOT_BEFORE, cert.getNotBefore());
            message.setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_NOT_AFTER, cert.getNotAfter());
        }
    } catch (SSLPeerUnverifiedException e) {
    // ignore
    }
}
Also used : SSLPeerUnverifiedException(javax.net.ssl.SSLPeerUnverifiedException) BigInteger(java.math.BigInteger) X509Certificate(javax.security.cert.X509Certificate) Principal(java.security.Principal)

Example 85 with SSLPeerUnverifiedException

use of javax.net.ssl.SSLPeerUnverifiedException in project xipki by xipki.

the class ClientCertCache method getTlsClientCert.

public static X509Certificate getTlsClientCert(HttpRequest request, SSLSession session, SslReverseProxyMode mode) throws IOException {
    if (mode == SslReverseProxyMode.NONE || mode == null) {
        if (session == null) {
            return null;
        }
        Certificate[] certs;
        try {
            certs = session.getPeerCertificates();
        } catch (SSLPeerUnverifiedException ex) {
            certs = null;
        }
        Certificate cert = (certs == null || certs.length < 1) ? null : certs[0];
        if (cert != null) {
            return (X509Certificate) cert;
        }
    } else if (mode != SslReverseProxyMode.APACHE) {
        throw new RuntimeException("Should not reach here, unknown SslReverseProxyMode " + mode);
    }
    // check whether this application is behind a reverse proxy and the TLS client certificate
    // is forwarded. Following headers should be configured to be forwarded:
    // SSL_CLIENT_VERIFY and SSL_CLIENT_CERT.
    // For more details please refer to
    // http://httpd.apache.org/docs/2.2/mod/mod_ssl.html#envvars
    // http://www.zeitoun.net/articles/client-certificate-x509-authentication-behind-reverse-proxy/start
    String clientVerify = request.headers().get("SSL_CLIENT_VERIFY");
    if (clientVerify == null || clientVerify.isEmpty()) {
        return null;
    }
    if (!"SUCCESS".equalsIgnoreCase(clientVerify.trim())) {
        return null;
    }
    String pemClientCert = request.headers().get("SSL_CLIENT_CERT");
    if (pemClientCert == null || pemClientCert.isEmpty()) {
        return null;
    }
    X509Certificate clientCert = clientCerts.get(pemClientCert);
    if (clientCert != null) {
        return clientCert;
    }
    try {
        String b64 = pemClientCert.replace("-----BEGIN CERTIFICATE-----", "").replace("-----END CERTIFICATE-----", "");
        byte[] encoded = Base64.getDecoder().decode(b64.getBytes(CharsetUtil.US_ASCII));
        clientCert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(encoded));
    } catch (CertificateException ex) {
        throw new IOException("could not parse Certificate", ex);
    }
    clientCerts.put(pemClientCert, clientCert);
    return clientCert;
}
Also used : ByteArrayInputStream(java.io.ByteArrayInputStream) SSLPeerUnverifiedException(javax.net.ssl.SSLPeerUnverifiedException) CertificateException(java.security.cert.CertificateException) IOException(java.io.IOException) X509Certificate(java.security.cert.X509Certificate) X509Certificate(java.security.cert.X509Certificate) Certificate(java.security.cert.Certificate)

Aggregations

SSLPeerUnverifiedException (javax.net.ssl.SSLPeerUnverifiedException)112 X509Certificate (java.security.cert.X509Certificate)40 Certificate (java.security.cert.Certificate)39 SSLSession (javax.net.ssl.SSLSession)27 SSLSocket (javax.net.ssl.SSLSocket)23 IOException (java.io.IOException)21 SSLException (javax.net.ssl.SSLException)15 CertificateException (java.security.cert.CertificateException)14 X509Certificate (javax.security.cert.X509Certificate)12 Principal (java.security.Principal)11 Test (org.junit.jupiter.api.Test)11 SSLHandshakeException (javax.net.ssl.SSLHandshakeException)10 InetSocketAddress (java.net.InetSocketAddress)8 SSLSocketFactory (javax.net.ssl.SSLSocketFactory)8 Test (org.junit.Test)8 UnknownHostException (java.net.UnknownHostException)7 CertificateEncodingException (java.security.cert.CertificateEncodingException)6 HttpsURLConnection (javax.net.ssl.HttpsURLConnection)6 SSLProtocolException (javax.net.ssl.SSLProtocolException)6 MockResponse (mockwebserver3.MockResponse)6