Commit 4a5f6011 authored by chiaming2000's avatar chiaming2000
Browse files

Preliminary protocol 3.0.0 support for pin operations (erase db ops only

. lock/unlock are not supported yet).

Setup and Security are also supported for the new protocol.

Commit the code so that other components can test with the simulator.

Code clean up will follow. 

 
parent 3e7949f4
Loading
Loading
Loading
Loading
+147 −7
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
 */
package com.seagate.kinetic.admin.impl;

import java.util.ArrayList;
import java.util.List;

import kinetic.admin.ACL;
@@ -25,24 +26,32 @@ import kinetic.admin.Domain;
import kinetic.admin.KineticAdminClient;
import kinetic.admin.KineticLog;
import kinetic.admin.KineticLogType;
import kinetic.admin.Role;
import kinetic.client.ClientConfiguration;
import kinetic.client.KineticClient;
import kinetic.client.KineticClientFactory;
import kinetic.client.KineticException;

import com.google.protobuf.ByteString;
//import com.google.protobuf.Message;
//import com.google.protobuf.Message.Builder;
import com.seagate.kinetic.client.internal.MessageFactory;
import com.seagate.kinetic.common.lib.HMACAlgorithmUtil;
import com.seagate.kinetic.common.lib.KineticMessage;
import com.seagate.kinetic.proto.Kinetic.Command;

import com.seagate.kinetic.proto.Kinetic.Command.GetLog;
import com.seagate.kinetic.proto.Kinetic.Command.GetLog.Type;
import com.seagate.kinetic.proto.Kinetic.Command.MessageType;
import com.seagate.kinetic.proto.Kinetic.Command.PinOperation.PinOpType;
import com.seagate.kinetic.proto.Kinetic.Command.Security;
import com.seagate.kinetic.proto.Kinetic.Command.Security.ACL.HMACAlgorithm;
import com.seagate.kinetic.proto.Kinetic.Command.Setup;
import com.seagate.kinetic.proto.Kinetic.Command.Status;
import com.seagate.kinetic.proto.Kinetic.Command.Status.StatusCode;
import com.seagate.kinetic.proto.Kinetic.Message.AuthType;
import com.seagate.kinetic.proto.Kinetic.Message.Builder;
import com.seagate.kinetic.proto.Kinetic.Message;
import com.seagate.kinetic.proto.Kinetic.Message.PINauth;

/**
 * This class provides administrative API for a kinetic administrator to
@@ -161,6 +170,37 @@ public class DefaultAdminClient implements KineticAdminClient {
    @Override
    public void instantErase(byte[] pin) throws KineticException {
        
        KineticMessage km = MessageFactory.createKineticMessageWithBuilder();
        
        Message.Builder mb = (Message.Builder) km.getMessage();
        mb.setAuthType(AuthType.PINAUTH);
        
        if (pin != null) {
            mb.setPinAuth(PINauth.newBuilder().setPin(ByteString.copyFrom(pin)));
        }
        
        Command.Builder commandBuilder = (Command.Builder) km.getCommand();
        
        commandBuilder.getHeaderBuilder()
        .setMessageType(MessageType.PINOP);
        
        commandBuilder.getBodyBuilder().getPinOpBuilder().setPinOpType(PinOpType.ERASE_PINOP);
        
        KineticMessage response = this.kineticClient.request(km);
        
        if (response.getCommand().getStatus().getCode() != StatusCode.SUCCESS) {
            
            KineticException ke = new KineticException ("erase db failed.");
            ke.setRequestMessage(km);
            ke.setResponseMessage(response);
            
            throw ke;
        }
    }
    
    //@Override
    public void instantEraseOld(byte[] pin) throws KineticException {

//        KineticMessage km = MessageFactory.createKineticMessageWithBuilder();
//
//        Message.Builder request = (Builder) km.getMessage();
@@ -244,7 +284,8 @@ public class DefaultAdminClient implements KineticAdminClient {
    }

    @Override
    public void setSecurity(List<ACL> acls) throws KineticException {
    public void setSecurity(List<ACL> acls, byte[] oldLockPin,
           byte[] newLockPin, byte[] oldErasePin, byte[] newErasePin) throws KineticException {

        KineticMessage km = MessageFactory.createKineticMessageWithBuilder();

@@ -280,6 +321,27 @@ public class DefaultAdminClient implements KineticAdminClient {

                acl.addScope(scope.build());
            }
            
            // set old lock pin
            if (oldLockPin != null) {
                security.setOldLockPIN(ByteString.copyFrom(oldLockPin));
            }
            
            // set new lock pin
            if (newLockPin != null) {
                security.setNewLockPIN(ByteString.copyFrom(newLockPin));
            }
            
            // set old erase pin
            if (oldErasePin != null) {
                security.setOldErasePIN (ByteString.copyFrom(oldErasePin));
            }
            
            // set new erase pin
            if (newErasePin != null) {
                security.setNewErasePIN (ByteString.copyFrom(newErasePin));
            }
            
            security.addAcl(acl.build());
        }

@@ -317,8 +379,53 @@ public class DefaultAdminClient implements KineticAdminClient {

    }
    
    
    private void setPinsWithDeafultAcl(byte[] oldLockPin, byte[] newLockPin,
            byte[] oldErasePin, byte[] newErasePin) throws KineticException {
        
        List<Role> roles = new ArrayList<Role>();
        roles.add(Role.DELETE);
        roles.add(Role.GETLOG);
        roles.add(Role.READ);
        roles.add(Role.RANGE);
        roles.add(Role.SECURITY);
        roles.add(Role.SETUP);
        roles.add(Role.WRITE);
        roles.add(Role.P2POP);

        Domain domain = new Domain();
        domain.setRoles(roles);

        List<Domain> domains = new ArrayList<Domain>();
        domains.add(domain);

        List<ACL> acls = new ArrayList<ACL>();
        ACL acl1 = new ACL();
        acl1.setDomains(domains);
        acl1.setUserId(1);
        acl1.setKey("asdfasdf");

        acls.add(acl1);

        this.setSecurity(acls, oldLockPin, newLockPin, oldErasePin, newErasePin);
    }

    @Override
    public void setup(byte[] pin, byte[] setPin, long newClusterVersion,
    public void setup(byte[] oldErasePin, byte[] newErasePin, long newClusterVersion,
            boolean secureErase) throws KineticException {
        
        this.setPinsWithDeafultAcl(null, null, oldErasePin, newErasePin);
        
        if (secureErase) {
            this.instantErase(newErasePin);
        }
        
        this.setClusterVersion(newClusterVersion);
        
    }
    
    //@Override
    public void _setup(byte[] pin, byte[] setPin, long newClusterVersion,
            boolean secureErase) throws KineticException {

        KineticMessage km = MessageFactory.createKineticMessageWithBuilder();
@@ -327,10 +434,6 @@ public class DefaultAdminClient implements KineticAdminClient {

        Setup.Builder setup = commandBuilder.getBodyBuilder()
                .getSetupBuilder();
        /**
         * XXX: protocol-3.0.0
         */
        
//
//        if (pin != null && pin.length > 0) {
//            setup.setPin(ByteString.copyFrom(pin));
@@ -370,6 +473,43 @@ public class DefaultAdminClient implements KineticAdminClient {

    }
    
    public void setClusterVersion (long newClusterVersion) throws KineticException {
        
        KineticMessage km = MessageFactory.createKineticMessageWithBuilder();
        
        Command.Builder commandBuilder = (Command.Builder) km.getCommand(); 

        Setup.Builder setup = commandBuilder.getBodyBuilder()
                .getSetupBuilder();
        
        if (0 > newClusterVersion) {
            throw new KineticException(
                    "Parameter invalid: new cluster version less than 0.");
        }
        
        setup.setNewClusterVersion(newClusterVersion);

        KineticMessage kmresp = configureSetupPolicy(km);

        if (kmresp.getCommand().getHeader().getMessageType() != MessageType.SETUP_RESPONSE) {
            throw new KineticException("received wrong message type.");
        }

        if (kmresp.getCommand().getStatus().getCode() == Status.StatusCode.NOT_AUTHORIZED) {

            throw new KineticException("Authorized Exception: "
                    + kmresp.getCommand().getStatus().getCode() + ": "
                    + kmresp.getCommand().getStatus().getStatusMessage());
        }

        if (kmresp.getCommand().getStatus().getCode() != Status.StatusCode.SUCCESS) {
            throw new KineticException("Unknown Error: "
                    + kmresp.getCommand().getStatus().getCode() + ": "
                    + kmresp.getCommand().getStatus().getStatusMessage());
        }

    }

    @Override
    public KineticLog getLog() throws KineticException {

+1 −1
Original line number Diff line number Diff line
@@ -161,7 +161,7 @@ public interface KineticAdminClient {
     * @see Domain
     * @see Role
     */
    public void setSecurity(List<ACL> acls) throws KineticException;
    public void setSecurity(List<ACL> acls, byte[] oldLockPin, byte[] newLockPin, byte[] oldErasePin, byte[] newErasePin) throws KineticException;

    /**
     * Erase all data in database for the drive.
+159 −0
Original line number Diff line number Diff line
/**
 * 
 * Copyright (C) 2014 Seagate Technology.
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */
package com.seagate.kinetic.simulator.internal;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.protobuf.ByteString;
import com.seagate.kinetic.common.lib.KineticMessage;
import com.seagate.kinetic.proto.Kinetic.Command;
import com.seagate.kinetic.proto.Kinetic.Command.PinOperation.PinOpType;
import com.seagate.kinetic.proto.Kinetic.Command.MessageType;
import com.seagate.kinetic.proto.Kinetic.Command.Setup;
import com.seagate.kinetic.proto.Kinetic.Command.Status.StatusCode;
import com.seagate.kinetic.simulator.persist.Store;

/**
 * 
 * Pin operation handler.
 *
 */
public abstract class PinOperationHandler {
    
    private final static Logger logger = Logger.getLogger(PinOperationHandler.class
            .getName());

    @SuppressWarnings("rawtypes")
    public static boolean handleOperation (KineticMessage request,
            KineticMessage respond, SecurityPin securityPin, Store store, String kineticHome) throws KVStoreException {
        
        boolean hasPermission = false;
        
        // remove set up in if erase db
        boolean removeSetup = false;

        Command.Builder commandBuilder = (Command.Builder) respond.getCommand();
        
        // set reply type
        commandBuilder.getHeaderBuilder()
        .setMessageType(MessageType.PINOP_RESPONSE);
        
        // set ack sequence
        commandBuilder.getHeaderBuilder()
        .setAckSequence(request.getCommand().getHeader().getSequence());
        
        // request pin
        ByteString requestPin = request.getMessage().getPinAuth().getPin();
        
        // request pin op type
        PinOpType pinOpType = request.getCommand().getBody().getPinOp().getPinOpType();
        
        switch (pinOpType) {
        case LOCK_PINOP:
            // check if has permission
            hasPermission = comparePin (requestPin, securityPin.getLockPin());
            if (hasPermission) {
                logger.info("Device locked ...");
            }
            break;
        case UNLOCK_PINOP:
            hasPermission = comparePin (requestPin, securityPin.getLockPin());
            if (hasPermission) {
                logger.info("Device unlocked ...");
            }
            break;
        case ERASE_PINOP:
            // Both erase operations will return
            // the device to an as manufactured state removing all
            // user data and configuration settings.
            // Erase the device. This may be secure
            // or not. The implication is that it may be faster
            // than the secure operation.
           
            hasPermission = comparePin (requestPin, securityPin.getErasePin());
            if (hasPermission) {
                store.reset();
                resetSetup (kineticHome);
                removeSetup = true;
            }
            break;
        case SECURE_ERASE_PINOP:
            // Erase the device in a way that will
            // physical access and disassembly of the device
            // will not
            hasPermission = comparePin (requestPin, securityPin.getErasePin());
            if (hasPermission) {
                store.reset();
                resetSetup (kineticHome);
                removeSetup = true;
            }
            break;
        case INVALID_PINOP:
            hasPermission = false;
            break;
       default: 
           hasPermission = false;
           break;
        }
        
        if (hasPermission == false) {
            commandBuilder.getStatusBuilder().setCode(StatusCode.NOT_AUTHORIZED);
            commandBuilder.getStatusBuilder().setStatusMessage("invalid pin: " + requestPin);
            
            logger.warning("unauthorized pin opeartion request, pin=" + requestPin);
        }
        
        return removeSetup;
    }
    
    private static void resetSetup(String kineticHome) {
        Setup.Builder sb = Setup.newBuilder();
        sb.setNewClusterVersion(0);
        try {
            SetupHandler.persistSetup(sb.build().toByteArray(), kineticHome);
        } catch (IOException e) {
            logger.log(Level.WARNING, e.getMessage(), e);
        }
    }
    
    /**
     * compare if request pin is equal to the device pin.
     * 
     * @param requestPin pin in the request message
     * @param devicePin device pin.
     * @return true if the same, otherwise return false
     */
    private static boolean comparePin (ByteString requestPin, ByteString devicePin) {
        
        boolean hasPermission = false;
        
        if (devicePin == null || devicePin.isEmpty()) {
            // if not set, set to true
            hasPermission = true;   
        } else if (devicePin.equals(requestPin)) {
            // if request pin is the same as drive pin
            hasPermission = true;
        }
        
        return hasPermission;
    }
}
+63 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.protobuf.ByteString;
import com.seagate.kinetic.common.lib.HMACAlgorithmUtil;
import com.seagate.kinetic.common.lib.KineticMessage;
import com.seagate.kinetic.common.lib.RoleUtil;
@@ -84,12 +85,14 @@ public abstract class SecurityHandler {

    public static synchronized Map<Long, ACL> handleSecurity(
            KineticMessage request, KineticMessage response,
            Map<Long, ACL> currentMap, String kineticHome)
            Map<Long, ACL> currentMap, SecurityPin securityPin, String kineticHome)
            throws KVStoreException, IOException {

        Command.Builder commandBuilder = (Command.Builder) response
                .getCommand();
        
        commandBuilder.getHeaderBuilder().setMessageType(MessageType.SECURITY_RESPONSE);

        List<ACL> aclList = request.getCommand().getBody().getSecurity()
                .getAclList();

@@ -135,10 +138,58 @@ public abstract class SecurityHandler {
            }
        }
        
        // get request security
        Security security = request.getCommand().getBody().getSecurity(); 
        
        // get current erase pin
        ByteString currentErasePin = securityPin.getErasePin();
        
        // need to compare if we need the old pin
        if ((currentErasePin != null) && (currentErasePin.isEmpty() == false)) {
            // get old erase pin
            ByteString oldErasePin = security.getOldErasePIN();
            
            // compare old with current
            if (currentErasePin.equals(oldErasePin) == false) {
                commandBuilder.getStatusBuilder().setCode(
                        StatusCode.NOT_AUTHORIZED);
                commandBuilder.getStatusBuilder().setStatusMessage(
                        "Invalid old erase pin: " + oldErasePin);
                
                return currentMap;
            } 
        }
        
        // get current lock pin
        ByteString currentLockPin = securityPin.getLockPin();
        
        // need to compare if we need the old pin
        if ((currentLockPin != null) && (currentLockPin.isEmpty() == false)) {
            // get old erase pin
            ByteString oldLockPin = security.getOldLockPIN();
            
            // compare old with current
            if (currentLockPin.equals(oldLockPin) == false) {
                commandBuilder.getStatusBuilder().setCode(
                        StatusCode.NOT_AUTHORIZED);
                commandBuilder.getStatusBuilder().setStatusMessage(
                        "Invalid old lock pin: " + oldLockPin);
                
                return currentMap;
            } 
        }
  
        // update acl map
        for (ACL acl : aclList) {
            currentMap.put(acl.getIdentity(), acl);
        }
        
        // set erase pin
        securityPin.setErasePin(security.getNewErasePIN());
              
        //set lock pin
        securityPin.setLockPin(security.getNewLockPIN());
        
        SecurityHandler.persistAcl(request.getCommand().getBody().getSecurity()
                .toByteArray(), kineticHome);
        
@@ -168,7 +219,7 @@ public abstract class SecurityHandler {
        out.close();
    }

    public static Map<Long, ACL> loadACL(String kineticHome) throws IOException {
    public static Map<Long, ACL> loadACL(String kineticHome, SecurityPin securityPin) throws IOException {
        String aclPersistFilePath = kineticHome + File.separator + ".acl";

        File aclFile = new File(aclPersistFilePath);
@@ -186,8 +237,16 @@ public abstract class SecurityHandler {
                for (ACL acl : aclList) {
                    aclMap.put(acl.getIdentity(), acl);
                }
                
                // set erase pin in cache
                securityPin.setErasePin(security.getNewErasePIN());
                
                // set lock pin in cache
                securityPin.setLockPin(security.getNewLockPIN());
            }
        }
        
        
        return aclMap;
    }
}
+31 −0
Original line number Diff line number Diff line
package com.seagate.kinetic.simulator.internal;

import com.google.protobuf.ByteString;

public class SecurityPin {
    
    private ByteString lockPin = null;
    
    private ByteString erasePin = null;

    public SecurityPin() {
        // TODO Auto-generated constructor stub
    }
    
    public void setLockPin (ByteString pin) {
        this.lockPin = pin;
    }
    
    public ByteString getLockPin() {
        return this.lockPin;
    }
    
    public void setErasePin (ByteString pin) {
        this.erasePin = pin;
    }
    
    public ByteString getErasePin() {
        return this.erasePin;
    }

}
Loading