Added plumbing code to use the concept of Authorizator into publish semantic

This commit is contained in:
andrea
2015-05-17 16:24:37 +02:00
parent 6d3fbc4591
commit f3ed351c61
16 changed files with 186 additions and 47 deletions
@@ -59,7 +59,7 @@ class ConfigurationParser {
m_properties.put(WEB_SOCKET_PORT_PROPERTY_NAME, Integer.toString(WEBSOCKET_PORT));
m_properties.put(PASSWORD_FILE_PROPERTY_NAME, "");
m_properties.put(PERSISTENT_STORE_PROPERTY_NAME, DEFAULT_PERSISTENT_PATH);
m_properties.put(ALLOW_ANONYMOUS, true);
m_properties.put(ALLOW_ANONYMOUS_PROPERTY_NAME, true);
}
/**
@@ -1,12 +0,0 @@
package org.eclipse.moquette.spi.impl;
import org.eclipse.moquette.server.IAuthenticator;
/**
* Created by andrea on 8/23/14.
*/
class AcceptAllAuthenticator implements IAuthenticator {
public boolean checkValid(String username, String password) {
return true;
}
}
@@ -28,6 +28,7 @@ import org.eclipse.moquette.spi.IMatchingCondition;
import org.eclipse.moquette.spi.IMessagesStore;
import org.eclipse.moquette.spi.ISessionsStore;
import org.eclipse.moquette.spi.impl.events.*;
import org.eclipse.moquette.spi.impl.security.IAuthorizator;
import org.eclipse.moquette.spi.impl.subscriptions.Subscription;
import org.eclipse.moquette.spi.impl.subscriptions.SubscriptionsStore;
import static org.eclipse.moquette.parser.netty.Utils.VERSION_3_1;
@@ -47,7 +48,7 @@ import org.eclipse.moquette.proto.messages.SubscribeMessage;
import org.eclipse.moquette.proto.messages.UnsubAckMessage;
import org.eclipse.moquette.proto.messages.UnsubscribeMessage;
import org.eclipse.moquette.server.ConnectionDescriptor;
import org.eclipse.moquette.server.IAuthenticator;
import org.eclipse.moquette.spi.impl.security.IAuthenticator;
import org.eclipse.moquette.server.ServerChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -98,6 +99,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
private Map<String, ConnectionDescriptor> m_clientIDs = new HashMap<>();
private SubscriptionsStore subscriptions;
private boolean allowAnonymous;
private IAuthorizator m_authorizator;
private IMessagesStore m_messagesStore;
private ISessionsStore m_sessionsStore;
private IAuthenticator m_authenticator;
@@ -117,14 +119,16 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
* @param sessionsStore the clients sessions store, used to persist subscriptions.
* @param authenticator the authenticator used in connect messages.
* @param allowAnonymous true connection to clients without credentials.
* @param authorizator used to apply ACL policies to publishes and subscriptions.
*/
void init(SubscriptionsStore subscriptions, IMessagesStore storageService,
ISessionsStore sessionsStore,
IAuthenticator authenticator,
boolean allowAnonymous) {
void init(SubscriptionsStore subscriptions, IMessagesStore storageService,
ISessionsStore sessionsStore,
IAuthenticator authenticator,
boolean allowAnonymous, IAuthorizator authorizator) {
//m_clientIDs = clientIDs;
this.subscriptions = subscriptions;
this.allowAnonymous = allowAnonymous;
m_authorizator = authorizator;
LOG.debug("subscription tree on init {}", subscriptions.dumpTree());
m_authenticator = authenticator;
m_messagesStore = storageService;
@@ -292,7 +296,10 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
final AbstractMessage.QOSType qos = msg.getQos();
final ByteBuffer message = msg.getPayload();
boolean retain = msg.isRetainFlag();
processPublish(clientID, topic, qos, message, retain, msg.getMessageID());
//check if the topic can be wrote
if (m_authorizator.canWrite(topic)) {
processPublish(clientID, topic, qos, message, retain, msg.getMessageID());
}
}
private void processPublish(String clientID, String topic, QOSType qos, ByteBuffer message, boolean retain, Integer messageID) {
@@ -20,7 +20,7 @@ import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import org.HdrHistogram.Histogram;
import org.eclipse.moquette.proto.messages.AbstractMessage;
import org.eclipse.moquette.server.IAuthenticator;
import org.eclipse.moquette.spi.impl.security.*;
import org.eclipse.moquette.server.ServerChannel;
import org.eclipse.moquette.spi.IMessagesStore;
import org.eclipse.moquette.spi.IMessaging;
@@ -34,6 +34,10 @@ import org.eclipse.moquette.spi.persistence.MapDBPersistentStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.text.ParseException;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
@@ -42,7 +46,8 @@ import java.util.concurrent.TimeUnit;
import static org.eclipse.moquette.commons.Constants.PASSWORD_FILE_PROPERTY_NAME;
import static org.eclipse.moquette.commons.Constants.PERSISTENT_STORE_PROPERTY_NAME;
import static org.eclipse.moquette.commons.Constants.ALLOW_ANONYMOUS;
import static org.eclipse.moquette.commons.Constants.ALLOW_ANONYMOUS_PROPERTY_NAME;
import static org.eclipse.moquette.commons.Constants.ACL_FILE_PROPERTY_NAME;
/**
*
@@ -198,8 +203,16 @@ public class SimpleMessaging implements IMessaging, EventHandler<ValueEvent> {
authenticator = new FileAuthenticator(configPath, passwdPath);
}
boolean allowAnonymous = Boolean.parseBoolean(props.getProperty(ALLOW_ANONYMOUS, "true"));
m_processor.init(subscriptions, m_storageService, m_sessionsStore, authenticator, allowAnonymous);
String aclFilePath = props.getProperty(ACL_FILE_PROPERTY_NAME, "");
IAuthorizator authorizator;
if (aclFilePath != null && !aclFilePath.isEmpty()) {
authorizator = new ACLAuthorizator(aclFilePath);
} else {
authorizator = new PermitAllAuthorizator();
}
boolean allowAnonymous = Boolean.parseBoolean(props.getProperty(ALLOW_ANONYMOUS_PROPERTY_NAME, "true"));
m_processor.init(subscriptions, m_storageService, m_sessionsStore, authenticator, allowAnonymous, authorizator);
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2012-2014 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package org.eclipse.moquette.spi.impl.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.text.ParseException;
import java.util.Collections;
import java.util.List;
/**
* @author andrea
*/
public class ACLAuthorizator implements IAuthorizator {
private static final Logger LOG = LoggerFactory.getLogger(ACLAuthorizator.class);
List<Authorization> authorisations = Collections.emptyList();
public ACLAuthorizator(String aclFilePath) {
File aclFile = new File(aclFilePath);
try {
authorisations = ACLFileParser.parse(aclFile);
} catch (ParseException pex) {
LOG.warn(String.format("Format error in parsing acl file %s", aclFile), pex);
}
}
@Override
public boolean canWrite(String topic) {
return false;
}
}
@@ -18,9 +18,7 @@ package org.eclipse.moquette.spi.impl.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.*;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
@@ -34,6 +32,27 @@ import static org.eclipse.moquette.spi.impl.security.Authorization.Permission;
public class ACLFileParser {
private static final Logger LOG = LoggerFactory.getLogger(ACLFileParser.class);
/**
* Parse the configuration from file.
*/
public static List<Authorization> parse(File file) throws ParseException {
if (file == null) {
LOG.warn("parsing NULL file, so fallback on default configuration!");
return Collections.emptyList();
}
if (!file.exists()) {
LOG.warn(String.format("parsing not existing file %s, so fallback on default configuration!", file.getAbsolutePath()));
return Collections.emptyList();
}
try {
FileReader reader = new FileReader(file);
return parse(reader);
} catch (FileNotFoundException fex) {
LOG.warn(String.format("parsing not existing file %s, so fallback on default configuration!", file.getAbsolutePath()), fex);
return Collections.emptyList();
}
}
/**
* Parse the ACL configuration file
*
@@ -0,0 +1,10 @@
package org.eclipse.moquette.spi.impl.security;
/**
* Created by andrea on 8/23/14.
*/
public class AcceptAllAuthenticator implements IAuthenticator {
public boolean checkValid(String username, String password) {
return true;
}
}
@@ -20,7 +20,7 @@ package org.eclipse.moquette.spi.impl.security;
*
* @author andrea
*/
class Authorization {
public class Authorization {
private String topic;
private Permission permission;
@@ -13,10 +13,9 @@
*
* You may elect to redistribute this code under either of these licenses.
*/
package org.eclipse.moquette.spi.impl;
package org.eclipse.moquette.spi.impl.security;
import org.apache.commons.codec.binary.Hex;
import org.eclipse.moquette.server.IAuthenticator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,7 +45,7 @@ public class FileAuthenticator implements IAuthenticator {
private Map<String, String> m_identities = new HashMap<>();
private MessageDigest m_digest;
FileAuthenticator(String parent, String filePath) {
public FileAuthenticator(String parent, String filePath) {
File file = new File(parent, filePath);
LOG.info("Loading password file: " + file);
if (file.isDirectory()) {
@@ -13,7 +13,7 @@
*
* You may elect to redistribute this code under either of these licenses.
*/
package org.eclipse.moquette.server;
package org.eclipse.moquette.spi.impl.security;
/**
* username and password checker
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2012-2014 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package org.eclipse.moquette.spi.impl.security;
/**
* ACL checker
*
* @author andrea
*/
public interface IAuthorizator {
/**
* Ask the implementation of the authorizator if the topic can be used in a publish.
* */
boolean canWrite(String topic);
}
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2012-2014 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package org.eclipse.moquette.spi.impl.security;
/**
* @author andrea
*/
public class PermitAllAuthorizator implements IAuthorizator {
@Override
public boolean canWrite(String topic) {
return true;
}
}