使用

要使用 Kerberos 进行身份验证的客户端应用程序代码必须针对 KDC 进行身份验证,并获取 Neo4j 服务的服务票证(在我们的示例中:neo4j/neo4j.windomain.local@WINDOMAIN.LOCAL)。服务票证必须使用Kerberos v5 (1.2.840.113554.1.2.2) 机制,直接或包装在SPNEGO (1.3.6.1.5.5.2) 中。

服务票证应通过以下属性在身份验证令牌中提供给 Neo4j 驱动程序

  • 主体:空

  • 凭据:Base64 编码的服务票证

  • 领域:add-on-Neo4j-Kerberos

请注意,Kerberos 附加组件目前不适用于 Neo4j 浏览器。它仅适用于使用 Neo4j 驱动程序的应用程序。

示例代码

示例 1. 使用 Java 的示例

这是一个使用 1.3 Java 驱动程序的示例实现。

public void connect()
{
	byte[] serviceTicket = get( serviceDomainName );

	String scheme = "ticket";
	String realm = "add-on-Neo4j-Kerberos";
	String encodedServiceTicket = Base64.getEncoder().encodeToString( serviceTicket );
  AuthToken token = AuthTokens.custom( encodedServiceTicket );

	try ( Driver driver = GraphDatabase.driver( "bolt://" + serviceDomainName, token ) )
	{
		// do interesting things
	}
}

public byte[] get( String serviceDomainName ) throws LoginException, GSSException
{
	Map<String,String> options = Collections.singletonMap( "useTicketCache", "true" );
	Krb5Configuration loginContextConfiguration = new Krb5Configuration( options );
	LoginContext loginContext = new LoginContext(
	    "KerberosClient",
	    null, // this is the subject
	    null, // no need for this
	    loginContextConfiguration
	  );
	loginContext.login();

	return getServiceTicket( loginContext.getSubject(), "neo4j@" + serviceDomainName );
}
public static final Oid SPNEGO_OID = getOid( "1.3.6.1.5.5.2" );
public byte[] getServiceTicket( Subject subject, String servicePrincipalName ) throws GSSException
{
	GSSManager manager = GSSManager.getInstance();
	GSSName serverName = manager.createName( servicePrincipalName, GSSName.NT_HOSTBASED_SERVICE );
	final GSSContext context = manager.createContext(
					serverName, SPNEGO_OID, null, GSSContext.DEFAULT_LIFETIME );
	// The GSS context initiation has to be performed as a privileged action.
	return Subject.doAs( subject, new PrivilegedAction<byte[]>()
	{
		public byte[] run()
		{
			try
			{
				// This is a one pass context initialisation.
				context.requestMutualAuth( false );
				context.requestCredDeleg( false );
				return context.initSecContext( new byte[0], 0, 0 );
			}
			catch ( GSSException e )
			{
				e.printStackTrace();
				return null;
			}
		}
	} );
}

private class Krb5Configuration extends Configuration
{
	private final AppConfigurationEntry[] configList;

	public Krb5Configuration( Map<String,String> options )
	{
		this.configList = new AppConfigurationEntry[1];
		configList[0] =
		    new AppConfigurationEntry(
		        "com.sun.security.auth.module.Krb5LoginModule",
		        AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
		        options
		    );
	}

	@Override
	public AppConfigurationEntry[] getAppConfigurationEntry( String name )
	{
	    return configList;
	}
}
示例 2. 使用 C# 的示例

这是一个使用 C# 和 1.3 .NET 驱动程序的示例实现。

var token = AuthTokens.kerberos(getTicket("neo4j"));
	using (var driver = GraphDatabase.Driver("bolt://neo4j.windomain.local:7687", token))
	{
		try
		{
			using (var session = driver.Session())
				{
					var result = session.Run("MATCH () RETURN count(*) AS count");
					foreach (var record in result)
					{
						Console.WriteLine($"Nodecount: {record["count"].As<string>()}");
					}
				}
		}
		catch (Exception e)
		{
			Console.WriteLine($"Error: {e.Message}");
		}
}

 private static String getTicket(string serviceName)
 {
	AppDomain.CurrentDomain.SetPrincipalPolicy(System.Security.Principal.PrincipalPolicy.WindowsPrincipal);
	var domain = Domain.GetCurrentDomain().ToString();

	using (var domainContext = new PrincipalContext(ContextType.Domain, domain))
	{
		string spn = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, serviceName).UserPrincipalName;
		Console.WriteLine("Service Principale name: " + spn);
		KerberosSecurityTokenProvider tokenProvider = new KerberosSecurityTokenProvider(spn);
		KerberosRequestorSecurityToken securityToken = tokenProvider.GetToken(TimeSpan.FromMinutes(1)) as KerberosRequestorSecurityToken;
		var token = securityToken.GetRequest();
		String ticket = Convert.ToBase64String(token);
		return ticket;
	}
 }