Pluggable_Storage_Auth


The Pluggable Storage + Auth example shows how a a plugin that overrides the builtin Sheet REST api Sheet plugin while it implements missing getprotected/setprotected methods.

After installing this plugin, you should be able to load a document from another server using the pluggable Auth and Storage techniques:

Installation is simple:

1. Compile the attached and put the output classfile anywhere in the Server classpath such as "<installdir>/lib/".

You will have to recreate package heirarchy in the lib folder such as "<installdir>/lib/com/someco/pluggables/"

2. Sheetster server configuration will require setting the auth to "stateless" to bypass sheetster stateful sessions

INSERT INTO LUMINET_CONFIG VALUES('pluggables',0,'session_mode','stateless',285,'If set to stateless this field will allow all permissions and data to be handled by the associated Auth objects. Do not add this value unless you are doing custom integration work','')

3. Now configure the storage settings
INSERT INTO LUMINET_CONFIG VALUES('pluggables',0,'storage_repository','http://<host>/CMS/files/',331,'The URL for the storage server','')
INSERT INTO LUMINET_CONFIG VALUES('pluggables',0,'storage_auth_ticket_name','ticket_id',332,'Set to the name of the session/request parameter used to track the authorized session ticket.','')
INSERT INTO LUMINET_CONFIG VALUES('pluggables',0,'storage_provider','Pluggable_Storage_Auth.Sample',333,'Set to the base-class name of the storage backend provider.','')

3. Restart the server

Please refer to the integration guide for details on how you can use callback URLs to load DocsFree sheetster inline to other app servers.

You can now build your own inline Pluggable Storages + Auth and integrate Sheetster as a front-end document editor for nearly any CMS or Document store.

 

SampleAuth.java
package Pluggable_Storage_Auth;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.extentech.ExtenXLS.ESS.WorkBookCommander;
import com.extentech.ExtenXLS.plugin.integration.AbstractAuth;
import com.extentech.ExtenXLS.plugin.integration.AuthException;
import com.extentech.ExtenXLS.plugin.integration.ServiceException;
import com.extentech.security.User;
import com.extentech.toolkit.Logger;

public class SampleAuth extends AbstractAuth {
    
      
    /**
     * Determines if the user has access to the specified resource
     *
     * 
     * @param resourceId object identifier, meme id, etc
     * @param user the user to check access
     * @return
     * @throws AuthException
     */
    public boolean hasResourceAccess(Object resourceId, User user) throws AuthException{
    	if(true)
    		return true;
        if(user.getAttribute("ReadWkBk")!=null && user.getAttribute("ReadWkBk").equals("true")) return true;
        try {
            SampleStorage storage = (SampleStorage)this.getStorage();
            storage.getInputStream(resourceId, user);
            user.setAttribute("ReadWkBk" + resourceId.toString(), "true");
            return true;
        }catch(Exception e) {
           throw new AuthException("Error checking resource access" + e);
        }
    }
    
    /**
     * Login a local user, add ticket
     * ------------------------------------------------------------
     * 
     * @author nick [ Feb 11, 2010 ]
     * @see com.extentech.ExtenXLS.plugin.integration.AbstractAuth#loginLocalUser(java.util.Map, com.extentech.security.User, java.lang.String, boolean)
     */
    public User loginLocalUser(Map parameters, User user, String password, boolean encryptpassword, boolean logincurrent)
    throws AuthException{
        user = super.loginLocalUser(parameters, user, password, encryptpassword, true);
        HttpServletRequest req = (HttpServletRequest)parameters.get(WorkBookCommander.REQUEST);
        if (req.getParameter("ticket_id")!=null) {
            user.setAttribute("ticket_id", req.getParameter("ticket_id").toString());
        }
        if (req.getParameter("uid")!=null) {
            try {
                user.setId(new Integer(req.getParameter("uid")).intValue());
            }catch (NumberFormatException e) {
                Logger.logErr("Error getting user id from Sample parameters " + e);
            }
            user.setAttribute("ticket_id", req.getParameter("ticket_id"));
        }
        return user;
    }
    
    /**
     * Handling security on a pass through, so 'public' doesnt really exist.  While I can find if the current
     * user has access or not, that does not tell me if other users do or do not.
     * */
    public boolean isPublic(String mid)  throws AuthException{
        return false;
    }
    
    public User getRemoteAuth(Map parameters, String uid, String provider)
            throws AuthException {
        // TODO Auto-generated method stub
        return null;
    }
    public String login(Map parameters) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }
    public boolean canConnect() throws ServiceException {
        // TODO Auto-generated method stub
        return false;
    }
    public String getProviderName() {
        return "Sample";
    }
}

SampleStorage.java
/** 
 * SampleStorage.java
 *
 * ##LICENSE##
 *
 * Jan 25, 2010
 *
 * @author John McMahon
 * 
 */
package Pluggable_Storage_Auth;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;
import com.extentech.ExtenXLS.DocumentHandle;
import com.extentech.ExtenXLS.plugin.integration.AbstractStorage;
import com.extentech.ExtenXLS.plugin.integration.StorageException;
import com.extentech.ExtenXLS.web.WebWorkBook;
import com.extentech.comm.MessageListener;
import com.extentech.luminet.Serve;
import com.extentech.luminet.ServeConnection;
import com.extentech.security.User;
import com.extentech.toolkit.Logger;
/** 
 * The Sample storage implementation.
 * 
 server configuration will require setting the auth to "stateless" to bypass sheetster stateful sessions
 
	INSERT INTO LUMINET_CONFIG VALUES('connect',0,'session_mode','stateless',285,'If set to stateless this field will allow all permissions and data to be handled by the associated Auth objects.  Do not add this value unless you are doing custom integration work','')
 configure the storage
	INSERT INTO LUMINET_CONFIG VALUES('connect',0,'storage_repository','http://<host>/@api/deki/files/',331,'The URL for the storage server','')
	INSERT INTO LUMINET_CONFIG VALUES('connect',0,'storage_auth_ticket_name','ticket_id',332,'Set to the name of the session/request parameter used to track the authorized session ticket.','')
	INSERT INTO LUMINET_CONFIG VALUES('connect',0,'storage_provider','Sample',333,'Set to the friendly name of the storage backend provider.','')
 * 
 * @author John McMahon :: May 10, 2011 :: Copyright &copy;2011 <a href = "http://www.extentech.com">Extentech Inc.</a>
 *
 */
public class SampleStorage extends AbstractStorage {
    private String url;
    private int docId = 1;
    
    public int getNewDocumentId() throws StorageException {
        return docId++;
    }
    /**
     * Instantiate a Sample storage.
     * 
     * A servletcontext is required in order to check for server-wide parameters
     * 
     * storage_repository
     * @author nick [ Feb 1, 2010 ]
     * @param srv
     */
    public SampleStorage(Serve srv) {
        this.setServe(srv);
        
        // this is a local host for testing, use the configured host in production
        url = "http://127.0.0.1/cmx/CMS/files/";
        if(srv.getInitParameter("storage_repository") != null)
            url = srv.getInitParameter("storage_repository");
    }
    /**
	 * 
	 * Get a workbook from the CMS.  
	 * 
	 * Sets the ticket on the user, along with a fileId on the workbook;
	 * 
	 * @see com.extentech.ExtenXLS.plugin.integration.Storage#getRemoteWorkBook(java.lang.Object, com.extentech.security.User, com.extentech.comm.MessageListener, java.lang.String)
	 */
	public DocumentHandle loadDocument(Object id, User user, MessageListener ml, Map parameters) throws StorageException {
        WebWorkBook bkx = null;
        try {
            InputStream in = this.getInputStream(id, user);
            bkx = new WebWorkBook(in, user);
            bkx.getMessageManager().registerClient(ml);
            bkx.addProperty("fileId", id);
            return bkx;
        } catch (MalformedURLException e) {
            throw new StorageException("URL Error initializing Sample workbook: " + e);
        } catch (IOException ex) {
            throw new StorageException("IO Error initializing Sample workbook: " + ex);
        }
	}
	
	/**
	 * Get an input stream to the Sample data source
	 * 
	 * @author nick [ Feb 11, 2010 ]
	 * @param id
	 * @param user
	 * @return
	 * @throws MalformedURLException
	 * @throws IOException
	 */
	protected InputStream getInputStream(Object id, User user)throws MalformedURLException, IOException {
	    String ticket = "";
	    if(user.getAttribute("ticket_id")!=null) ticket = user.getAttribute("ticket_id").toString();
	    String thisUrl = url + id;
	    thisUrl += "?ticket_id=" + ticket; // sadly setting headers does not seem to work.
        URL urlx = new URL(thisUrl);
        URLConnection uc = urlx.openConnection();
        //uc.setRequestProperty ("Authorization", "Basic " + ticket);  // no workie!  see GET string addition above.
        String contentType = uc.getContentType();
        int contentLength = uc.getContentLength();
        if (contentType.startsWith("text/") || contentLength == -1) {
          throw new IOException("This is not a binary file.");
        } 
        InputStream raw = uc.getInputStream();
        InputStream in = new BufferedInputStream(raw);
        return in;
	}
	/**
	 * store a workbook back to Sample
	 * 
	 * 
	 * @see com.extentech.ExtenXLS.plugin.integration.Storage#storeWorkBook(java.lang.Object, com.extentech.security.User, com.extentech.comm.MessageListener, java.lang.String)
	 */
	public boolean storeDocument(DocumentHandle dh, User user) throws Exception {
	    WebWorkBook bkx = (WebWorkBook)dh;
    	String ticket = user.getAttribute("ticket_id").toString();
        // get the Sample provider URL
        if(getServe().getInitParameter("storage_repository") != null) // default / for testing... 
        	url = getServe().getInitParameter("storage_repository");
        String id = (bkx.getProperty("fileId").toString());
        try{   
        url += id;
        url += "?ticket_id=" + ticket; // sadly setting headers does not seem to work.
        URL urlx = new URL(url);
        // create the PUT connection
        HttpURLConnection  uc = (HttpURLConnection) urlx.openConnection();
        uc.setDoOutput(true);
        uc.setUseCaches(false);
        uc.setRequestMethod( "PUT" );
        byte[] btxl = bkx.getBytes();
        int contlen = btxl.length;
        uc.setRequestProperty("Content-Length",String.valueOf(contlen));
	
		// POST the book bytes back to the Sample store
		OutputStream xout = uc.getOutputStream();
	    BufferedOutputStream out = new BufferedOutputStream(xout);
	    out.write(btxl);
	    
	    // TODO: implement this more efficient but how to handle content-length?
	    // bkx.write(out);
	    
	    xout.flush();
	    xout.close();
	    out.flush();
	    out.close();
	    
	    int res = uc.getResponseCode();
	    Logger.logInfo("PluginWorkBook.save to Sample returned: " + res);
	    if(res!=ServeConnection.SC_OK){
	        throw new StorageException("PluginWorkBook.save to Sample failed server response: " + res);
	    }
		// return null;
     }catch(Exception e){
 		throw new StorageException(e.toString());
 	}	
	
     return true;
	}
    /**
     * create a new document
     * @see com.extentech.ExtenXLS.plugin.integration.Storage#createDocument(java.lang.Object, com.extentech.security.User, com.extentech.comm.MessageListener, java.util.Map)
     */
    public DocumentHandle createDocument(Object id, User user,
            MessageListener ml, Map parameters) throws StorageException {
        Logger.logErr("New document creation not implemented.");
        return null;
    }
	/**
	 * @see com.extentech.ExtenXLS.plugin.integration.Storage#listDocuments(com.extentech.security.User, java.util.Map)
	 */
	public Object listDocuments(User user, Map parameters)
			throws StorageException {
		// TODO Auto-generated method stub
		return null;
	}
}