Skip to content

Instantly share code, notes, and snippets.

@nikos
Created January 28, 2015 15:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nikos/9c0ddd662b493738fbcc to your computer and use it in GitHub Desktop.
Save nikos/9c0ddd662b493738fbcc to your computer and use it in GitHub Desktop.
Sample AuthenticationProvider for Spring using MarkLogic Server (version 7)
package de.nava.mlsample.security;
import de.nava.mlsample.service.MarkLogicConnections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author Niko Schmuck
*/
@Service
public class MarkLogicAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider {
private static final Logger logger = LoggerFactory.getLogger(MarkLogicAuthenticationProvider.class);
@Autowired
protected MarkLogicConnections connections;
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
logger.info("Trying to retrieve user {} ...", username);
String password = (String) authentication.getCredentials();
boolean success = connections.auth(username, password);
if (!success) {
throw new UsernameNotFoundException("Unknown user: " + username);
}
Collection<GrantedAuthority> authorities = new ArrayList<>();
// TODO: will be improved by using user profiles
authorities.add(new SimpleGrantedAuthority("USER"));
if (username.toLowerCase().contains("admin")) {
authorities.add(new SimpleGrantedAuthority("ADMIN"));
}
return new User(username, password, authorities);
}
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
// Nothing to do here...
}
}
package de.nava.mlsample.service;
import com.marklogic.client.DatabaseClient;
import com.marklogic.client.DatabaseClientFactory;
import com.marklogic.client.admin.QueryOptionsManager;
import com.marklogic.client.admin.ServerConfigurationManager;
import com.marklogic.client.document.JSONDocumentManager;
import com.marklogic.client.document.XMLDocumentManager;
import com.marklogic.client.query.QueryManager;
import com.marklogic.client.query.SuggestDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.Map;
/**
* Provide access to connections via the MarkLogic API based on user accounts.
*/
@Service
public class MarkLogicConnections {
private static final Logger logger = LoggerFactory.getLogger(MarkLogicConnections.class);
@Value("${marklogic.host}")
private String host;
@Value("${marklogic.port}")
private int port;
@Value("${search.pagelength}")
private int defaultPageLength;
private Map<String, DatabaseClient> clients = new HashMap<>();
public synchronized boolean auth(String username, String password) {
logger.info("Setting up connection to MarkLogic server {}:{} for user {} ...", host, port, username);
try {
DatabaseClient client = DatabaseClientFactory.newClient(host, port, username, password,
DatabaseClientFactory.Authentication.DIGEST);
// ~~
testQuery(client);
logger.info("Successfully logged in {}", username);
clients.put(username, client);
return true;
} catch (Exception e) {
logger.warn("Unable to login user {}: {}", username, e.getMessage());
return false;
}
}
/**
* Provoke an exception in case a user cannot be logged in.
* com.marklogic.client.FailedRequestException
* Local message: Suggest call failed: Unauthorized. Server Message: Unauthorized
*/
private void testQuery(DatabaseClient client) {
QueryManager queryManager = client.newQueryManager();
SuggestDefinition suggestDefinition = queryManager.newSuggestDefinition();
queryManager.suggest(suggestDefinition);
}
/**
* Throws an IllegalArgumentException in case no database client can be found
* for the given username.
*/
public DatabaseClient getDatabaseClient(String username) {
DatabaseClient dbClient = clients.get(username);
Assert.notNull(dbClient, "No database client for '" + username + "' found, better auth first");
return dbClient;
}
public void release(String username) {
clients.remove(username);
}
// ~~
public ServerConfigurationManager getServerConfigManager(String username) {
return getDatabaseClient(username).newServerConfigManager();
}
@Cacheable("mlConnections")
public QueryManager getQueryManager(String username) {
QueryManager queryManager = getDatabaseClient(username).newQueryManager();
queryManager.setPageLength(defaultPageLength);
return queryManager;
}
public QueryOptionsManager getQueryOptionManager(String username) {
return getServerConfigManager(username).newQueryOptionsManager();
}
@Cacheable("mlXMLDocMgr")
public XMLDocumentManager getXMLDocumentManager(String username) {
return getDatabaseClient(username).newXMLDocumentManager();
}
@Cacheable("mlJSONDocMgr")
public JSONDocumentManager getJSONDocumentManager(String username) {
return getDatabaseClient(username).newJSONDocumentManager();
}
}
@nikos
Copy link
Author

nikos commented Feb 20, 2015

Recommendation for testQuery (L62) to switch from suggest to a document exists query (although that is probably a matter of only some milliseconds, anyways):

JSONDocumentManager jsonDocMgr = client.newJSONDocumentManager();
jsonDocMgr.exists("/foo/bar.json");  

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment