Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

better support for application level authentication #2322

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions MIGRATION_HINTS_4.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ In some cases `SHA384` was misspelled as `SHA378`. That's fixed but causes also

Supports virtual threads for DTLS receivers, if the JVM supports it. Otherwise platform daemon threads are used. Chosen by `-1` as number of threads in `DTLS.RECEIVER_THREAD_COUNT`.

The `DTLSConnector` uses Connection ID to identify DLTS context now also for outgoing messages, if available.

The `DefaultCipherSuiteSelector` supports now `CertificateAuthenticationMode.WANTED` even if no common client certificate type is available. It omits the `CertificateRequest` in this case.

The `InMemoryConnectionStore` removes now `Connection`s without `Principals` when the ip-address is reused.

Using the `DTLS.APPLICATION_AUTHORIZATION_TIMEOUT` removes now connections with anonymous clients after that timeout, if the application doesn't authorize them using the `ApplicationAuthorizer`.

### Element-Connector-TCP-Netty:

### Californium-Core:
Expand Down Expand Up @@ -120,6 +128,12 @@ Remove the "Advanced" from PSK-stores. Replace `AdvancedPskStore` by `PskStore`,

Remove the "NewAdvanced" from CertificateVerifier. Replace `NewAdvancedCertificateVerifier` by `CertificateVerifier`, `StaticNewAdvancedCertificateVerifier` by `StaticCertificateVerifier` and `AsyncNewAdvancedCertificateVerifier` by `AsyncCertificateVerifier`.

Rename `Connection.refreshAutoResumptionTime` into `updateLastMessageNanos`.

`DTLSConnector.cleanupRecentHandshakes` returns `int` instead of `void`.

Remove `restoreConnection` from `DTLSConnector`.

### Californium-Core:

The functions of the obsolete and removed `ExtendedCoapStack` are moved into
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
import org.eclipse.californium.elements.RawDataChannel;
import org.eclipse.californium.elements.UDPConnector;
import org.eclipse.californium.elements.UdpMulticastConnector;
import org.eclipse.californium.elements.auth.ApplicationAuthorizer;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.util.ClockUtil;
import org.eclipse.californium.elements.util.DaemonThreadFactory;
Expand Down Expand Up @@ -229,6 +230,13 @@ public class CoapEndpoint implements Endpoint, Executor {
/** The connector over which the endpoint connects to the network */
private final Connector connector;

/**
* Application authorizer for anonymous client support.
*
* @since 4.0
*/
private final ApplicationAuthorizer authorizer;

private final String scheme;

/**
Expand Down Expand Up @@ -389,6 +397,7 @@ protected CoapEndpoint(Connector connector, Configuration config, TokenGenerator
}
this.config = config;
this.connector = connector;
this.authorizer = (connector instanceof ApplicationAuthorizer) ? (ApplicationAuthorizer) connector : null;
this.connector.setRawDataReceiver(new InboxImpl());
this.scheme = CoAP.getSchemeForProtocol(connector.getProtocol());
this.multicastBaseMid = config.get(CoapConfig.MULTICAST_BASE_MID);
Expand Down Expand Up @@ -1339,6 +1348,11 @@ public void cancelObservation(Token token) {
matcher.cancelObserve(token);
}

@Override
public ApplicationAuthorizer getApplicationAuthorizer() {
return authorizer;
}

/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.eclipse.californium.core.observe.NotificationListener;
import org.eclipse.californium.core.server.MessageDeliverer;
import org.eclipse.californium.elements.Connector;
import org.eclipse.californium.elements.auth.ApplicationAuthorizer;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.util.ProtocolScheduledExecutorService;

Expand Down Expand Up @@ -286,4 +287,13 @@ public interface Endpoint {
* @throws IllegalArgumentException if the token has client-local scope.
*/
void cancelObservation(Token token);

/**
* Gets application authorizer.
*
* @return application authorizer, or {@code null}, if not supported by this
* endpoint.
* @since 4.0
*/
ApplicationAuthorizer getApplicationAuthorizer();
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.eclipse.californium.core.config.CoapConfig.MatcherMode;
import org.eclipse.californium.elements.Connector;
import org.eclipse.californium.elements.EndpointContextMatcher;
import org.eclipse.californium.elements.PrincipalAndAnonymousEndpointContextMatcher;
import org.eclipse.californium.elements.PrincipalEndpointContextMatcher;
import org.eclipse.californium.elements.RelaxedDtlsEndpointContextMatcher;
import org.eclipse.californium.elements.StrictDtlsEndpointContextMatcher;
Expand All @@ -43,64 +44,106 @@
*/
public class EndpointContextMatcherFactory {


/**
* Create endpoint context matcher related to connector according the
* Creates endpoint context matcher related to connector according the
* configuration.
*
* If connector supports "coaps:", RESPONSE_MATCHING is used to determine,
* if {@link StrictDtlsEndpointContextMatcher},
* <p>
* If connector supports "DTLS", COAP.RESPONSE_MATCHING is used to
* determine, if {@link StrictDtlsEndpointContextMatcher},
* {@link RelaxedDtlsEndpointContextMatcher}, or
* {@link PrincipalEndpointContextMatcher} is used.
*
* If connector supports "coap:", RESPONSE_MATCHING is used to determine, if
* {@link UdpEndpointContextMatcher} is used with disabled
* <p>
* If connector supports "UDP", COAP.RESPONSE_MATCHING is used to determine,
* if {@link UdpEndpointContextMatcher} is used with disabled
* ({@link MatcherMode#RELAXED}) or enabled address check (otherwise).
*
* <p>
* For other protocol flavors the corresponding matcher is used.
*
* @param connector connector to create related endpoint context matcher.
* @param config configuration.
* @return endpoint context matcher
* @since 3.0 (changed parameter to Configuration)
* @throws NullPointerException if one of the provided arguments is
* {@code null}
* @throws IllegalArgumentException if the protocol of the connector is not
* supported.
* @since 4.0 (added exceptions)
*/
public static EndpointContextMatcher create(Connector connector, Configuration config) {
String protocol = null;
if (null != connector) {
protocol = connector.getProtocol();
if (CoAP.PROTOCOL_TCP.equalsIgnoreCase(protocol)) {
return new TcpEndpointContextMatcher();
} else if (CoAP.PROTOCOL_TLS.equalsIgnoreCase(protocol)) {
return new TlsEndpointContextMatcher();
}
if (connector == null) {
throw new NullPointerException("Connector must not be null!");
}
return create(connector.getProtocol(), false, config);
}

/**
* Creates endpoint context matcher related to the protocol according the
* configuration.
* <p>
* For "DTLS" COAP.RESPONSE_MATCHING is used to determine, if
* {@link StrictDtlsEndpointContextMatcher},
* {@link RelaxedDtlsEndpointContextMatcher}, or
* {@link PrincipalEndpointContextMatcher} is used. If PRINCIPAL_IDENTITY is
* used for COAP.RESPONSE_MATCHING and anonymous clients are enabled, then
* {@link PrincipalAndAnonymousEndpointContextMatcher} is used. Anonymous
* clients are only implemented for DTLS, see
* DTLS.CLIENT_AUTHENTICATION_MODE and DTLS.DTLS_APPLICATION_AUTHORIZATION.
* <p>
* For "UDP", COAP.RESPONSE_MATCHING is used to determine, if
* {@link UdpEndpointContextMatcher} is used with disabled
* ({@link MatcherMode#RELAXED}) or enabled address check (otherwise).
* <p>
* For other protocol flavors the corresponding matcher is used.
*
* @param protocol protocol.
* @param anonymous {@code true} if anonymous clients must be supported.
* @param config configuration.
* @return endpoint context matcher
* @throws NullPointerException if one of the provided arguments is
* {@code null}
* @throws IllegalArgumentException if the protocol is not supported.
* @since 4.0
*/
public static EndpointContextMatcher create(String protocol, boolean anonymous, Configuration config) {
if (protocol == null) {
throw new NullPointerException("Protocol must not be null!");
}
if (config == null) {
throw new NullPointerException("Configuration must not be null!");
}
if (CoAP.PROTOCOL_TCP.equalsIgnoreCase(protocol)) {
return new TcpEndpointContextMatcher();
} else if (CoAP.PROTOCOL_TLS.equalsIgnoreCase(protocol)) {
return new TlsEndpointContextMatcher();
}

MatcherMode mode = config.get(CoapConfig.RESPONSE_MATCHING);
switch (mode) {
case RELAXED:
if (CoAP.PROTOCOL_UDP.equalsIgnoreCase(protocol)) {
if (CoAP.PROTOCOL_UDP.equalsIgnoreCase(protocol)) {
switch (mode) {
case RELAXED:
return new UdpEndpointContextMatcher(false);
} else {
return new RelaxedDtlsEndpointContextMatcher();
}
case PRINCIPAL:
if (CoAP.PROTOCOL_UDP.equalsIgnoreCase(protocol)) {
return new UdpEndpointContextMatcher(true);
} else {
return new PrincipalEndpointContextMatcher();
}
case PRINCIPAL_IDENTITY:
if (CoAP.PROTOCOL_UDP.equalsIgnoreCase(protocol)) {
case PRINCIPAL:
case PRINCIPAL_IDENTITY:
case STRICT:
default:
return new UdpEndpointContextMatcher(true);
} else {
return new PrincipalEndpointContextMatcher(true);
}
case STRICT:
default:
if (CoAP.PROTOCOL_UDP.equalsIgnoreCase(protocol)) {
return new UdpEndpointContextMatcher(true);
} else {
} else if (CoAP.PROTOCOL_DTLS.equalsIgnoreCase(protocol)) {
switch (mode) {
case RELAXED:
return new RelaxedDtlsEndpointContextMatcher();
case PRINCIPAL:
return new PrincipalEndpointContextMatcher();
case PRINCIPAL_IDENTITY:
if (anonymous) {
return new PrincipalAndAnonymousEndpointContextMatcher();
} else {
return new PrincipalEndpointContextMatcher(true);
}
case STRICT:
default:
return new StrictDtlsEndpointContextMatcher();
}
}
throw new IllegalArgumentException("Protocol " + protocol + " is not supported!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import org.eclipse.californium.elements.EndpointContext;
import org.eclipse.californium.elements.EndpointIdentityResolver;
import org.eclipse.californium.elements.UdpMulticastConnector;
import org.eclipse.californium.elements.auth.ApplicationAuthorizer;
import org.eclipse.californium.elements.util.CheckedExecutor;
import org.eclipse.californium.elements.util.ClockUtil;
import org.eclipse.californium.elements.util.SerialExecutor;
Expand Down Expand Up @@ -861,6 +862,18 @@ public Object getPeersIdentity() {
return peersIdentity;
}

/**
* Gets application authorizer.
*
* @return application authorizer, or {@code null}, if not supported by this
* exchange.
* @since 4.0
*/
public ApplicationAuthorizer getApplicationAuthorizer() {
Endpoint endpoint = getEndpoint();
return endpoint == null ? null : endpoint.getApplicationAuthorizer();
}

/**
* Indicated, that this exchange retransmission reached the timeout.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ public static State onResponse(ObserveRelation relation, Response response) {
}
boolean noNotification = result == State.NONE || result == State.CANCELED;
if (response.isNotification() && (!response.isSuccess() || noNotification)) {
LOGGER.warn("Application notification, not longer observing, remove observe-option {}", response);
LOGGER.info("Application notification, not longer observing, remove observe-option {}", response);
response.getOptions().removeObserve();
}
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.security.Principal;

import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.coap.CoAP.Code;
Expand All @@ -37,6 +38,7 @@
import org.eclipse.californium.elements.EndpointContext;
import org.eclipse.californium.elements.MapBasedEndpointContext;
import org.eclipse.californium.elements.MapBasedEndpointContext.Attributes;
import org.eclipse.californium.elements.auth.ApplicationAuthorizer;
import org.eclipse.californium.elements.UdpMulticastConnector;

/**
Expand Down Expand Up @@ -69,32 +71,64 @@ public CoapExchange(Exchange exchange) {
this.exchange = exchange;
}

/**
* Gets the source principal.
*
* @return the source principal. May be {@code null}, if source is
* anonymous.
* @since 4.0
*/
public final Principal getSourcePrincipal() {
return getSourceContext().getPeerIdentity();
}

/**
* Gets the source context.
*
* @return the source context.
* @since 4.0
*/
public final EndpointContext getSourceContext() {
return exchange.getRequest().getSourceContext();
}

/**
* Gets the source socket address of the request.
*
* @return the source socket address
* @since 2.1
*/
public InetSocketAddress getSourceSocketAddress() {
return exchange.getRequest().getSourceContext().getPeerAddress();
public final InetSocketAddress getSourceSocketAddress() {
return getSourceContext().getPeerAddress();
}

/**
* Gets the source address of the request.
*
* @return the source address
*/
public InetAddress getSourceAddress() {
return exchange.getRequest().getSourceContext().getPeerAddress().getAddress();
public final InetAddress getSourceAddress() {
return getSourceSocketAddress().getAddress();
}

/**
* Gets the source port of the request.
*
* @return the source port
*/
public int getSourcePort() {
return exchange.getRequest().getSourceContext().getPeerAddress().getPort();
public final int getSourcePort() {
return getSourceSocketAddress().getPort();
}

/**
* Gets application authorizer.
*
* @return application authorizer, or {@code null}, if not supported by this
* exchange.
* @since 4.0
*/
public ApplicationAuthorizer getApplicationAuthorizer() {
return exchange.getApplicationAuthorizer();
}

/**
Expand Down
Loading