Skip to content
This repository has been archived by the owner on Jan 3, 2019. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Add authenticated access to Fedora repo.
  • Loading branch information
nikhiltri authored and Andrew Woods committed Apr 30, 2014
1 parent 800759c commit b89273c
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 72 deletions.
30 changes: 30 additions & 0 deletions README.md
Expand Up @@ -187,3 +187,33 @@ Use the following MAVEN_OPTS on build
### Caveat: Blank Nodes

Fedora doesn't currently support blank nodes.

## Authenticated repo

If REST calls to your Fedora repository require BASIC authentication,
you'll need to set two system variables in your servlet container,
`fcrepo.username` and `fcrepo.password`. In Jetty/Maven 3, you can set
some values in your [settings.xml](https://maven.apache.org/settings.html)
file that will later be set to these two system variables:

``` xml
<profiles>
<profile>
<id>fcrepo</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<fedora.repo.username>example</fedora.repo.username>
<fedora.repo.password>xxxxxxxx</fedora.repo.password>
</properties>
</profile>
</profiles>
```

In Tomcat 7 you can set the following command line options in
your `conf/setenv.sh` file:

``` sh
JAVA_OPTS="$JAVA_OPTS -Dfcrepo.username=example -Dfcrepo.password=xxxxxxxx "
```
Expand Up @@ -21,8 +21,13 @@
import com.hp.hpl.jena.rdf.model.NodeIterator;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;
import org.apache.http.client.HttpClient;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.fcrepo.kernel.utils.EventType;
import org.slf4j.Logger;
Expand All @@ -31,6 +36,7 @@
import javax.jms.Message;
import javax.jms.MessageListener;
import java.io.Reader;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;

Expand All @@ -41,6 +47,7 @@
import static com.hp.hpl.jena.vocabulary.RDF.type;
import static java.lang.Integer.MAX_VALUE;
import static javax.jcr.observation.Event.NODE_REMOVED;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.fcrepo.kernel.RdfLexicon.HAS_CHILD;
import static org.fcrepo.kernel.RdfLexicon.REPOSITORY_NAMESPACE;
import static org.slf4j.LoggerFactory.getLogger;
Expand All @@ -58,11 +65,11 @@ public class IndexerGroup implements MessageListener {

private static final Logger LOGGER = getLogger(IndexerGroup.class);

private String repositoryURL;
private final String repositoryURL;

private Set<Indexer<Object>> indexers;
private final Set<Indexer<Object>> indexers;

private HttpClient httpClient;
private final DefaultHttpClient httpClient;

private Set<String> reindexed;

Expand Down Expand Up @@ -111,65 +118,62 @@ public class IndexerGroup implements MessageListener {
/**
* Default constructor.
**/
public IndexerGroup() {
LOGGER.debug("Creating IndexerGroup: {}", this);
final PoolingClientConnectionManager connMann =
new PoolingClientConnectionManager();
public IndexerGroup(final String repositoryURL,
final Set<Indexer<Object>> indexers,
final String fedoraUsername,
final String fedoraPassword) {
this(repositoryURL, indexers, createHttpClient(repositoryURL, fedoraUsername, fedoraPassword));
}

protected static DefaultHttpClient createHttpClient(final String repositoryURL,
final String fedoraUsername,
final String fedoraPassword) {
final PoolingClientConnectionManager connMann = new PoolingClientConnectionManager();
connMann.setMaxTotal(MAX_VALUE);
connMann.setDefaultMaxPerRoute(MAX_VALUE);
this.httpClient = new DefaultHttpClient(connMann);
}

/**
* Set repository URL.
**/
public void setRepositoryURL(final String repositoryURL) {
this.repositoryURL = repositoryURL;
}
final DefaultHttpClient httpClient = new DefaultHttpClient(connMann);
httpClient.setRedirectStrategy(new DefaultRedirectStrategy());
httpClient.setHttpRequestRetryHandler(new StandardHttpRequestRetryHandler(0, false));

/**
* Get repository URL.
**/
public String getRepositoryURL() {
return repositoryURL;
}
// If the Fedora instance requires authentication, set it up here
if (!isBlank(fedoraUsername) && !isBlank(fedoraPassword)) {
LOGGER.debug("Adding BASIC credentials to client for repo requests.");

/**
* Set indexers for this group.
*
* @param indexers
*/
public void setIndexers(final Set<Indexer<Object>> indexers) {
this.indexers = indexers;
LOGGER.debug("Using indexer complement: {} ", indexers);
}
URI fedoraUri = URI.create(repositoryURL);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(fedoraUri.getHost(), fedoraUri.getPort()),
new UsernamePasswordCredentials(fedoraUsername, fedoraPassword));

/**
* Get indexers set for this group.
*
* @return indexers
*/
public Set<Indexer<Object>> getIndexers() {
return indexers;
httpClient.setCredentialsProvider(credsProvider);
}

return httpClient;
}

/**
* Set HttpClient for this group. In the constructor a default is set
* but this allows it to be customized.
*
* @param client
* Constructor
*/
public void setHttpClient(final HttpClient client) {
this.httpClient = client;
public IndexerGroup(final String repositoryURL,
final Set<Indexer<Object>> indexers,
final DefaultHttpClient httpClient) {
LOGGER.debug("Creating IndexerGroup: {}", this);

assert (null != repositoryURL);
this.repositoryURL = repositoryURL;

assert (indexers.size() > 0);
this.indexers = indexers;

assert (null != httpClient);
this.httpClient = httpClient;
}

/**
* Gets the HttpClient used by this class.
*
* @return
*/
public HttpClient getHttpClient() {
return this.httpClient;
* Get repository URL.
**/
public String getRepositoryURL() {
return repositoryURL;
}

/**
Expand Down Expand Up @@ -231,7 +235,7 @@ private void index( final String uri, final String eventType ) {
}
}

for (final Indexer<Object> indexer : getIndexers()) {
for (final Indexer<Object> indexer : indexers) {
LOGGER.debug("Operating for indexer: {}", indexer);
Boolean hasContent = false;
Object content = EMPTY_CONTENT;
Expand Down
Expand Up @@ -16,16 +16,25 @@

package org.fcrepo.indexer;

import junit.framework.Assert;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.fcrepo.kernel.utils.EventType;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import javax.jms.JMSException;
import javax.jms.Message;
Expand All @@ -36,8 +45,9 @@
import static javax.jcr.observation.Event.NODE_ADDED;
import static javax.jcr.observation.Event.PROPERTY_CHANGED;
import static org.fcrepo.kernel.RdfLexicon.REPOSITORY_NAMESPACE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
Expand All @@ -51,14 +61,16 @@
/**
* @author Michael Durbin
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({"javax.net.ssl.*", "org.slf4j.*", "javax.xml.parsers.*", "org.apache.xerces.*"})
@PrepareForTest({DefaultHttpClient.class})
public class IndexerGroupTest {

private IndexerGroup indexerGroup;

private String repoUrl;

@Mock
private HttpClient httpClient;
private DefaultHttpClient httpClient;

private Set<Indexer<Object>> indexers;

Expand All @@ -68,23 +80,33 @@ public class IndexerGroupTest {
@Before
public void setUp() {
initMocks(this);
httpClient = PowerMockito.mock(DefaultHttpClient.class);

repoUrl = "fake:fake";
repoUrl = "http://example.org:80";

indexers = new HashSet<Indexer<Object>>();
indexers = new HashSet<>();
indexers.add(indexer);

indexerGroup = new IndexerGroup();
indexerGroup.setHttpClient(httpClient);
indexerGroup.setIndexers(indexers);
indexerGroup.setRepositoryURL(repoUrl);
indexerGroup = new IndexerGroup(repoUrl, indexers, httpClient);
}

@Test
public void testGetters() {
public void testSanityConstructor() {
indexerGroup = new IndexerGroup(repoUrl, indexers, "user", "pass");
assertEquals(repoUrl, indexerGroup.getRepositoryURL());
assertEquals(indexers, indexerGroup.getIndexers());
assertEquals(httpClient, indexerGroup.getHttpClient());
}

@Test
public void testCreateHttpClient() {
DefaultHttpClient client = IndexerGroup.createHttpClient(repoUrl, "user", "pass");
assertNotNull(client);

CredentialsProvider provider = client.getCredentialsProvider();
Credentials credentials = provider.getCredentials(new AuthScope("example.org", 80));
assertNotNull("Credentials should not be null!", credentials);

assertEquals("user", credentials.getUserPrincipal().getName());
assertEquals("pass", credentials.getPassword());
}

@Test
Expand Down
Expand Up @@ -18,6 +18,7 @@
import static com.hp.hpl.jena.graph.NodeFactory.createURI;
import static com.hp.hpl.jena.graph.Triple.create;
import static com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel;
import static org.apache.http.HttpStatus.SC_FORBIDDEN;
import static org.apache.http.HttpStatus.SC_NOT_FOUND;
import static org.apache.http.HttpStatus.SC_OK;
import static org.junit.Assert.assertTrue;
Expand All @@ -41,7 +42,6 @@
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.rdf.model.Model;


public class RdfRetrieverTest {

private RdfRetriever testRetriever;
Expand Down Expand Up @@ -90,7 +90,6 @@ public void testSimpleRetrieval() throws IOException {
final Model result = testRetriever.get();
assertTrue("Didn't find our test triple!", result.contains(result
.asStatement(testTriple)));

}

@Test(expected = RuntimeException.class)
Expand Down Expand Up @@ -119,4 +118,27 @@ public void testYetOtherFailedRetrieval() throws IOException {
new RdfRetriever(testId, mockClient).get();
}

@Test
public void testAuthRetrieval() throws IOException {
final String testId = "testAuthRetrieval";
final Model input = createDefaultModel();
input.add(input.asStatement(testTriple));
when(mockStatusLine.getStatusCode()).thenReturn(SC_OK);
try (StringWriter w = new StringWriter()) {
input.write(w, "N3");
try (
InputStream rdf =
new ByteArrayInputStream(w.toString().getBytes())) {
when(mockEntity.getContent()).thenReturn(rdf);
}
}
new RdfRetriever(testId, mockClient).get();
}

@Test(expected = RuntimeException.class)
public void testAuthForbiddenRetrieval(){
final String testId = "testAuthForbiddenRetrieval";
when(mockStatusLine.getStatusCode()).thenReturn(SC_FORBIDDEN);
new RdfRetriever(testId, mockClient).get();
}
}
Expand Up @@ -50,15 +50,17 @@

<!-- Message Driven POJO (MDP) that manages individual indexers -->
<bean id="indexerGroup" class="org.fcrepo.indexer.IndexerGroup">
<property name="repositoryURL" value="http://localhost:${test.port:8080}"/>
<property name="indexers">
<constructor-arg name="repositoryURL" value="http://localhost:${test.port:8080}"/>
<constructor-arg name="indexers">
<set value-type="org.fcrepo.indexer.Indexer">
<ref bean="testIndexer"/>
<ref bean="fileSerializer"/>
<ref bean="sparqlUpdate"/>
<ref bean="solrIndexer"/>
</set>
</property>
</constructor-arg>
<constructor-arg name="fedoraUsername" value=""/>
<constructor-arg name="fedoraPassword" value=""/>
</bean>

</beans>

0 comments on commit b89273c

Please sign in to comment.