/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License
* at:
*
* http://opensource.org/licenses/ecl2.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.opencastproject.engage.theodul.manager.impl;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Map;
public class StaticResourceClassloaderTest {
private static final Logger logger = LoggerFactory.getLogger(StaticResourceClassloaderTest.class);
private final String overrideDirName = "theodul.override.test";
private final String resourceFilename = "test.resource";
private final String genuineResourceName = "other.resource";
private final String bundlePath = "ui/";
private final String bundleURLPrefix = "http://localhost/";
private final String overriddenBundleResource = bundlePath + resourceFilename;
private final String overriddenResourceURL = bundleURLPrefix + bundlePath + resourceFilename;
private final String genuineBundleResource = bundlePath + genuineResourceName;
private final String genuineResourceURL = bundleURLPrefix + bundlePath + genuineResourceName;
private File overrideDir;
private File overrideResource;
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
@Before
public void setUp() throws Exception {
// create override directory and resource
try {
File tempFolder = testFolder.newFolder("folder");
overrideDir = new File(tempFolder, overrideDirName);
overrideResource = new File(overrideDir, resourceFilename);
overrideDir.mkdir();
logger.info("Creating {}", overrideResource);
if (overrideResource.createNewFile()) {
// write something to ensure file existence
PrintWriter writer = new PrintWriter(overrideResource);
writer.print("Override Test Resource");
writer.flush();
writer.close();
} else {
throw new IOException("Failed to create " + overrideResource.getAbsolutePath());
}
} catch (IOException ex) {
throw new RuntimeException("Failed to properly set up override direcory. ", ex);
}
}
@Test
public void testBundleResourceLoading() throws Exception {
StaticResourceClassloader klas = new StaticResourceClassloader(new MockBundle(), overrideDir, bundlePath);
URL result = klas.getResource(genuineBundleResource);
Assert.assertNotNull(result);
Assert.assertEquals(new URL(genuineResourceURL), result);
}
@Test
public void testFielesystemResourceOverriding() throws Exception {
StaticResourceClassloader klas = new StaticResourceClassloader(new MockBundle(), overrideDir, bundlePath);
URL result = klas.getResource(overriddenBundleResource);
Assert.assertNotNull(result);
Assert.assertEquals(overrideResource.toURI().toURL(), result);
}
@Test
public void testMaliciousPath() {
// test if absolut paths are not working
StaticResourceClassloader klas = new StaticResourceClassloader(new MockBundle(), overrideDir, bundlePath);
URL result = klas.getResource("/etc/hostname");
Assert.assertNull(result);
// test if relative ascending paths are not working
result = klas.getResource("../../etc/hostname");
Assert.assertNull(result);
}
@After
public void cleanUp() throws Exception {
overrideResource.delete();
overrideDir.delete();
}
class MockBundle implements Bundle {
@Override
public String getSymbolicName() {
return MockBundle.class.getSimpleName();
}
@Override
public URL getResource(String path) {
try {
if (path.endsWith(genuineBundleResource)) {
return new URL(genuineResourceURL);
} else if (path.endsWith(overriddenBundleResource)) {
return new URL(overriddenResourceURL);
}
} catch (MalformedURLException ex) {
throw new RuntimeException("Could not instantiate URL object.", ex);
}
return null;
}
//<editor-fold defaultstate="collapsed" desc="Unused methods from Bundle interface.">
@Override
public int getState() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void start(int i) throws BundleException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void start() throws BundleException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void stop(int i) throws BundleException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void stop() throws BundleException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void update(InputStream in) throws BundleException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void update() throws BundleException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void uninstall() throws BundleException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Dictionary getHeaders() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public long getBundleId() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getLocation() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public ServiceReference[] getRegisteredServices() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public ServiceReference[] getServicesInUse() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public boolean hasPermission(Object o) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Dictionary getHeaders(String string) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Class loadClass(String string) throws ClassNotFoundException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Enumeration getResources(String string) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Enumeration getEntryPaths(String string) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public URL getEntry(String string) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public long getLastModified() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Enumeration findEntries(String string, String string1, boolean bln) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public BundleContext getBundleContext() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Map getSignerCertificates(int i) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Version getVersion() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public int compareTo(Bundle o) {
return 0;
}
@Override
public <A> A adapt(Class<A> type) {
return null;
}
@Override
public File getDataFile(String filename) {
return null;
}
//</editor-fold>
}
}