Search in sources :

Example 1 with Connection

use of org.jivesoftware.openfire.Connection in project Openfire by igniterealtime.

the class ExternalClientSaslServer method evaluateResponse.

@Override
public byte[] evaluateResponse(byte[] response) throws SaslException {
    if (isComplete()) {
        throw new IllegalStateException("Authentication exchange already completed.");
    }
    // There will be no further steps. Either authentication succeeds or fails, but in any case, we're done.
    complete = true;
    final Connection connection = session.getConnection();
    Certificate[] peerCertificates = connection.getPeerCertificates();
    if (peerCertificates == null || peerCertificates.length < 1) {
        throw new SaslException("No peer certificates.");
    }
    final X509Certificate trusted;
    if (SASLAuthentication.SKIP_PEER_CERT_REVALIDATION_CLIENT.getValue()) {
        // Trust that the peer certificate has been validated when TLS got established.
        trusted = (X509Certificate) peerCertificates[0];
    } else {
        // Re-evaluate the validity of the peer certificate.
        final TrustStore trustStore = connection.getConfiguration().getTrustStore();
        trusted = trustStore.getEndEntityCertificate(peerCertificates);
    }
    if (trusted == null) {
        throw new SaslException("Certificate chain of peer is not trusted.");
    }
    // Process client identities / principals.
    final ArrayList<String> principals = new ArrayList<>();
    principals.addAll(CertificateManager.getClientIdentities(trusted));
    String principal;
    switch(principals.size()) {
        case 0:
            principal = "";
            break;
        default:
            Log.debug("More than one principal found, using the first one.");
        // intended fall-through;
        case 1:
            principal = principals.get(0);
            break;
    }
    // Process requested user name.
    String username;
    if (response != null && response.length > 0) {
        username = new String(response, StandardCharsets.UTF_8);
        if (PROPERTY_SASL_EXTERNAL_CLIENT_SUPPRESS_MATCHING_REALMNAME.getValue() && username.contains("@")) {
            String userUser = username.substring(0, username.lastIndexOf("@"));
            String userRealm = username.substring((username.lastIndexOf("@") + 1));
            if (XMPPServer.getInstance().getServerInfo().getXMPPDomain().equals(userRealm)) {
                username = userUser;
            }
        }
    } else {
        username = null;
    }
    if (username == null || username.length() == 0) {
        // cause an authorization failure.
        for (String princ : principals) {
            final String mappedUsername = AuthorizationManager.map(princ);
            if (!mappedUsername.equals(princ)) {
                username = mappedUsername;
                principal = princ;
                break;
            }
        }
        if (username == null || username.length() == 0) {
            // Still no username.  Punt.
            username = principal;
        }
        Log.debug("No username requested, using: {}", username);
    }
    // Its possible that either/both username and principal are null here. The providers should not allow a null authorization
    if (AuthorizationManager.authorize(username, principal)) {
        Log.debug("Principal {} authorized to username {}", principal, username);
        authorizationID = username;
        // Success!
        return null;
    }
    throw new SaslException();
}
Also used : Connection(org.jivesoftware.openfire.Connection) ArrayList(java.util.ArrayList) TrustStore(org.jivesoftware.openfire.keystore.TrustStore) SaslException(javax.security.sasl.SaslException) X509Certificate(java.security.cert.X509Certificate) X509Certificate(java.security.cert.X509Certificate) Certificate(java.security.cert.Certificate)

Example 2 with Connection

use of org.jivesoftware.openfire.Connection in project Openfire by igniterealtime.

the class SASLAuthentication method getSASLMechanismsElement.

public static Element getSASLMechanismsElement(LocalIncomingServerSession session) {
    final Element result = DocumentHelper.createElement(new QName("mechanisms", new Namespace("", SASL_NAMESPACE)));
    if (session.isSecure()) {
        final Connection connection = session.getConnection();
        final TrustStore trustStore = connection.getConfiguration().getTrustStore();
        final X509Certificate trusted = trustStore.getEndEntityCertificate(session.getConnection().getPeerCertificates());
        boolean haveTrustedCertificate = trusted != null;
        if (trusted != null && session.getDefaultIdentity() != null) {
            haveTrustedCertificate = verifyCertificate(trusted, session.getDefaultIdentity());
        }
        if (haveTrustedCertificate) {
            // Offer SASL EXTERNAL only if TLS has already been negotiated and the peer has a trusted cert.
            final Element mechanism = result.addElement("mechanism");
            mechanism.setText("EXTERNAL");
        }
    }
    // OF-2072: Return null instead of an empty element, if so configured.
    if (JiveGlobals.getBooleanProperty("sasl.server.suppressEmpty", false) && result.elements().isEmpty()) {
        return null;
    }
    return result;
}
Also used : QName(org.dom4j.QName) Element(org.dom4j.Element) Connection(org.jivesoftware.openfire.Connection) TrustStore(org.jivesoftware.openfire.keystore.TrustStore) Namespace(org.dom4j.Namespace) X509Certificate(java.security.cert.X509Certificate)

Example 3 with Connection

use of org.jivesoftware.openfire.Connection in project Openfire by igniterealtime.

the class StreamManager method startResume.

private void startResume(String namespace, String previd, long h) {
    Log.debug("Attempting resumption for {}, h={}", previd, h);
    this.namespace = namespace;
    // Ensure that resource binding has NOT occurred.
    if (!allowResume()) {
        Log.debug("Unable to process session resumption attempt, as session {} is in a state where session resumption is not allowed.", session);
        sendUnexpectedError();
        return;
    }
    if (session.getStatus() == Session.STATUS_AUTHENTICATED) {
        Log.debug("Unable to process session resumption attempt, as session {} is not authenticated.", session);
        sendUnexpectedError();
        return;
    }
    AuthToken authToken = null;
    // Ensure that resource binding has occurred.
    if (session instanceof ClientSession) {
        authToken = ((LocalClientSession) session).getAuthToken();
    }
    if (authToken == null) {
        Log.debug("Unable to process session resumption attempt, as session {} does not provide any auth context.", session);
        sendUnexpectedError();
        return;
    }
    // Decode previd.
    String resource;
    String streamId;
    try {
        StringTokenizer toks = new StringTokenizer(new String(StringUtils.decodeBase64(previd), StandardCharsets.UTF_8), "\0");
        resource = toks.nextToken();
        streamId = toks.nextToken();
    } catch (Exception e) {
        Log.debug("Exception from previd decode:", e);
        sendUnexpectedError();
        return;
    }
    final JID fullJid;
    if (authToken.isAnonymous()) {
        fullJid = new JID(resource, session.getServerName(), resource, true);
    } else {
        fullJid = new JID(authToken.getUsername(), session.getServerName(), resource, true);
    }
    Log.debug("Resuming session for '{}'. Current session: {}", fullJid, session.getStreamID());
    // Locate existing session.
    final ClientSession route = XMPPServer.getInstance().getRoutingTable().getClientRoute(fullJid);
    if (route == null) {
        sendError(new PacketError(PacketError.Condition.item_not_found));
        return;
    }
    if (!(route instanceof LocalClientSession)) {
        Log.debug("Not allowing a client of '{}' to resume a session on this cluster node. The session can only be resumed on the Openfire cluster node where the original session was connected.", fullJid);
        sendError(new PacketError(PacketError.Condition.unexpected_request));
        return;
    }
    final LocalClientSession otherSession = (LocalClientSession) route;
    if (!otherSession.getStreamID().getID().equals(streamId)) {
        sendError(new PacketError(PacketError.Condition.item_not_found));
        return;
    }
    Log.debug("Found existing session for '{}', checking status", fullJid);
    // Previd identifies proper session. Now check SM status
    if (!otherSession.getStreamManager().resume) {
        Log.debug("Not allowing a client of '{}' to resume a session, the session to be resumed does not have the stream management resumption feature enabled.", fullJid);
        sendError(new PacketError(PacketError.Condition.unexpected_request));
        return;
    }
    if (otherSession.getStreamManager().namespace == null) {
        Log.debug("Not allowing a client of '{}' to resume a session, the session to be resumed disabled SM functionality as a response to an earlier error.", fullJid);
        sendError(new PacketError(PacketError.Condition.unexpected_request));
        return;
    }
    if (!otherSession.getStreamManager().namespace.equals(namespace)) {
        Log.debug("Not allowing a client of '{}' to resume a session, the session to be resumed used a different version ({}) of the session management resumption feature as compared to the version that's requested now: {}.", fullJid, otherSession.getStreamManager().namespace, namespace);
        sendError(new PacketError(PacketError.Condition.unexpected_request));
        return;
    }
    if (!otherSession.getStreamManager().validateClientAcknowledgement(h)) {
        Log.debug("Not allowing a client of '{}' to resume a session, as it reports it received more stanzas from us than that we've send it.", fullJid);
        sendError(new PacketError(PacketError.Condition.unexpected_request));
        return;
    }
    if (!otherSession.isDetached()) {
        Log.debug("Existing session {} of '{}' is not detached; detaching.", otherSession.getStreamID(), fullJid);
        Connection oldConnection = otherSession.getConnection();
        otherSession.setDetached();
        oldConnection.close();
    }
    Log.debug("Attaching to other session '{}' of '{}'.", otherSession.getStreamID(), fullJid);
    // If we're all happy, re-attach the connection from the pre-existing session to the new session, discarding the old session.
    otherSession.reattach(session, h);
    Log.debug("Perform resumption of session {} for '{}', using connection from session {}", otherSession.getStreamID(), fullJid, session.getStreamID());
}
Also used : LocalClientSession(org.jivesoftware.openfire.session.LocalClientSession) StringTokenizer(java.util.StringTokenizer) LocalClientSession(org.jivesoftware.openfire.session.LocalClientSession) ClientSession(org.jivesoftware.openfire.session.ClientSession) Connection(org.jivesoftware.openfire.Connection) AuthToken(org.jivesoftware.openfire.auth.AuthToken) UnauthorizedException(org.jivesoftware.openfire.auth.UnauthorizedException) UnknownHostException(java.net.UnknownHostException)

Example 4 with Connection

use of org.jivesoftware.openfire.Connection in project Openfire by igniterealtime.

the class LocalSession method deliverRawText.

@Override
public void deliverRawText(String text) {
    Connection connection = conn;
    if (connection == null) {
        Log.debug("Unable to deliver raw text in session with address {} and streamID {}, as its connection is null. Dropping: {}", this.address, this.streamID, text);
        return;
    }
    connection.deliverRawText(text);
}
Also used : Connection(org.jivesoftware.openfire.Connection) SocketConnection(org.jivesoftware.openfire.net.SocketConnection)

Example 5 with Connection

use of org.jivesoftware.openfire.Connection in project Openfire by igniterealtime.

the class LocalIncomingServerSession method createSession.

/**
     * Creates a new session that will receive packets. The new session will be authenticated
     * before being returned. If the authentication process fails then the answer will be
     * <tt>null</tt>.<p>
     *
     * @param serverName hostname of this server.
     * @param reader reader on the new established connection with the remote server.
     * @param connection the new established connection with the remote server.
     * @return a new session that will receive packets or null if a problem occured while
     *         authenticating the remote server or when acting as the Authoritative Server during
     *         a Server Dialback authentication process.
     * @throws org.xmlpull.v1.XmlPullParserException if an error occurs while parsing the XML.
     * @throws java.io.IOException if an input/output error occurs while using the connection.
     */
public static LocalIncomingServerSession createSession(String serverName, XMPPPacketReader reader, SocketConnection connection) throws XmlPullParserException, IOException {
    XmlPullParser xpp = reader.getXPPParser();
    String version = xpp.getAttributeValue("", "version");
    String fromDomain = xpp.getAttributeValue("", "from");
    String toDomain = xpp.getAttributeValue("", "to");
    int[] serverVersion = version != null ? decodeVersion(version) : new int[] { 0, 0 };
    if (toDomain == null) {
        toDomain = serverName;
    }
    try {
        // Get the stream ID for the new session
        StreamID streamID = SessionManager.getInstance().nextStreamID();
        // Create a server Session for the remote server
        LocalIncomingServerSession session = SessionManager.getInstance().createIncomingServerSession(connection, streamID, fromDomain);
        // Send the stream header
        StringBuilder openingStream = new StringBuilder();
        openingStream.append("<stream:stream");
        openingStream.append(" xmlns:db=\"jabber:server:dialback\"");
        openingStream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
        openingStream.append(" xmlns=\"jabber:server\"");
        openingStream.append(" from=\"").append(toDomain).append("\"");
        if (fromDomain != null) {
            openingStream.append(" to=\"").append(fromDomain).append("\"");
        }
        openingStream.append(" id=\"").append(streamID).append("\"");
        // implementations appears to reduce connection issues with those domains (patch by Marcin Cieślak).
        if (serverVersion[0] >= 1) {
            openingStream.append(" version=\"1.0\">");
        } else {
            openingStream.append('>');
        }
        connection.deliverRawText(openingStream.toString());
        if (serverVersion[0] >= 1) {
            // Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection (and server dialback)
            // Indicate the TLS policy to use for this connection
            Connection.TLSPolicy tlsPolicy = connection.getTlsPolicy();
            boolean hasCertificates = false;
            try {
                hasCertificates = XMPPServer.getInstance().getCertificateStoreManager().getIdentityStore(ConnectionType.SOCKET_S2S).getStore().size() > 0;
            } catch (Exception e) {
                Log.error(e.getMessage(), e);
            }
            if (Connection.TLSPolicy.required == tlsPolicy && !hasCertificates) {
                Log.error("Server session rejected. TLS is required but no certificates " + "were created.");
                return null;
            }
            connection.setTlsPolicy(hasCertificates ? tlsPolicy : Connection.TLSPolicy.disabled);
        }
        // Indicate the compression policy to use for this connection
        connection.setCompressionPolicy(connection.getConfiguration().getCompressionPolicy());
        StringBuilder sb = new StringBuilder();
        if (serverVersion[0] >= 1) {
            // Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection (and server dialback)
            // Don't offer stream-features to pre-1.0 servers, as it confuses them. Sending features to Openfire < 3.7.1 confuses it too - OF-443) 
            sb.append("<stream:features>");
            if (JiveGlobals.getBooleanProperty(ConnectionSettings.Server.TLS_ENABLED, true)) {
                sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">");
                if (!ServerDialback.isEnabled()) {
                    // Server dialback is disabled so TLS is required
                    sb.append("<required/>");
                }
                sb.append("</starttls>");
            }
            // Include available SASL Mechanisms
            sb.append(SASLAuthentication.getSASLMechanisms(session));
            if (ServerDialback.isEnabled()) {
                // Also offer server dialback (when TLS is not required). Server dialback may be offered
                // after TLS has been negotiated and a self-signed certificate is being used
                sb.append("<dialback xmlns=\"urn:xmpp:features:dialback\"><errors/></dialback>");
            }
            sb.append("</stream:features>");
        }
        connection.deliverRawText(sb.toString());
        // Set the domain or subdomain of the local server targeted by the remote server
        session.setLocalDomain(serverName);
        return session;
    } catch (Exception e) {
        Log.error("Error establishing connection from remote server:" + connection, e);
        connection.close();
        return null;
    }
}
Also used : StreamID(org.jivesoftware.openfire.StreamID) XmlPullParser(org.xmlpull.v1.XmlPullParser) Connection(org.jivesoftware.openfire.Connection) SocketConnection(org.jivesoftware.openfire.net.SocketConnection) KeyStoreException(java.security.KeyStoreException) UnauthorizedException(org.jivesoftware.openfire.auth.UnauthorizedException) IOException(java.io.IOException) XmlPullParserException(org.xmlpull.v1.XmlPullParserException)

Aggregations

Connection (org.jivesoftware.openfire.Connection)13 UnauthorizedException (org.jivesoftware.openfire.auth.UnauthorizedException)4 SocketConnection (org.jivesoftware.openfire.net.SocketConnection)4 LocalClientSession (org.jivesoftware.openfire.session.LocalClientSession)4 UnknownHostException (java.net.UnknownHostException)3 StreamID (org.jivesoftware.openfire.StreamID)3 TrustStore (org.jivesoftware.openfire.keystore.TrustStore)3 XmlPullParserException (org.xmlpull.v1.XmlPullParserException)3 IOException (java.io.IOException)2 X509Certificate (java.security.cert.X509Certificate)2 Element (org.dom4j.Element)2 Namespace (org.dom4j.Namespace)2 QName (org.dom4j.QName)2 XmlPullParser (org.xmlpull.v1.XmlPullParser)2 KeyStoreException (java.security.KeyStoreException)1 Certificate (java.security.cert.Certificate)1 ArrayList (java.util.ArrayList)1 StringTokenizer (java.util.StringTokenizer)1 SaslException (javax.security.sasl.SaslException)1 WriteException (org.apache.mina.core.write.WriteException)1