Created
January 28, 2015 15:01
-
-
Save nikos/9c0ddd662b493738fbcc to your computer and use it in GitHub Desktop.
Sample AuthenticationProvider for Spring using MarkLogic Server (version 7)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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... | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Recommendation for testQuery (L62) to switch from suggest to a document exists query (although that is probably a matter of only some milliseconds, anyways):