All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hcl.domino.jna.admin.JNAIdVault Maven / Gradle / Ivy

There is a newer version: 1.41.0
Show newest version
/*
 * ==========================================================================
 * Copyright (C) 2019-2022 HCL America, Inc. ( http://www.hcl.com/ )
 *                            All rights reserved.
 * ==========================================================================
 * Licensed under the  Apache 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 .
 *
 * 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 com.hcl.domino.jna.admin;

import java.lang.ref.ReferenceQueue;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.EnumSet;

import com.hcl.domino.DominoClient.OpenDatabase;
import com.hcl.domino.DominoException;
import com.hcl.domino.admin.idvault.UserId;
import com.hcl.domino.commons.admin.IDefaultIdVault;
import com.hcl.domino.commons.errors.INotesErrorConstants;
import com.hcl.domino.commons.gc.APIObjectAllocations;
import com.hcl.domino.commons.gc.IAPIObject;
import com.hcl.domino.commons.gc.IGCDominoClient;
import com.hcl.domino.commons.util.NotesErrorUtils;
import com.hcl.domino.data.IAdaptable;
import com.hcl.domino.exception.IncompatibleImplementationException;
import com.hcl.domino.jna.BaseJNAAPIObject;
import com.hcl.domino.jna.data.JNADatabase;
import com.hcl.domino.jna.internal.NotesNamingUtils;
import com.hcl.domino.jna.internal.NotesStringUtils;
import com.hcl.domino.jna.internal.capi.NotesCAPI;
import com.hcl.domino.jna.internal.gc.allocations.JNAIdVaultAllocations;
import com.hcl.domino.misc.NotesConstants;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.ptr.ShortByReference;

public class JNAIdVault extends BaseJNAAPIObject implements IDefaultIdVault {

	public JNAIdVault(IAPIObject parent) {
		super(parent);
		
		setInitialized();
	}

	@SuppressWarnings("rawtypes")
	@Override
	protected JNAIdVaultAllocations createAllocations(IGCDominoClient parentDominoClient,
			APIObjectAllocations parentAllocations, ReferenceQueue queue) {
		return new JNAIdVaultAllocations(parentDominoClient, parentAllocations, this, queue);
	}
	
	@Override
	public String extractUserIdFromVault(String userName, String password, Path idPath, String serverName) {
		checkDisposed();
		
		return _getUserIdFromVault(userName, password, idPath, null, serverName);
	}

	@Override
	@SuppressWarnings("unchecked")
	public UserId getUserIdFromVault(String userName, String password, String serverName) {
		checkDisposed();
		
		PointerByReference rethKFC = new PointerByReference();
		_getUserIdFromVault(userName, password, null, rethKFC, serverName);
		
		//according to core dev, calling SECKFMClose is not required / not used in core platform code.
		boolean noDispose = true;
		return new JNAUserId(this, new IAdaptable() {
			
			@Override
			public  T getAdapter(Class clazz) {
				if (PointerByReference.class == clazz) {
					return (T) rethKFC;
				} else if(Long.class.equals(clazz)) {
					return (T)Long.valueOf(Pointer.nativeValue(rethKFC.getPointer()));
				}

				return null;
			}
		}, noDispose);
	}

	@Override
	public String putUserIdIntoVault(String userName, String password, Path idPath, String serverName) {
		checkDisposed();
		
		return _putUserIdIntoVault(userName, password, idPath, null, serverName);
	}

	@Override
	public String putUserIdIntoVault(String userName, String password, UserId userId, String serverName) {
		checkDisposed();
		
		if (!(userId instanceof JNAUserId)) {
			throw new IncompatibleImplementationException(userId, JNAUserId.class);
		}
		PointerByReference phKFC = null;
		
		if (userId!=null) {
			phKFC = userId.getAdapter(PointerByReference.class);
		}

		if (phKFC==null) {
			throw new DominoException("Could not retrieve required user id handle");
		}

		return _putUserIdIntoVault(userName, password, null, phKFC, serverName);
	}

	@Override
	public SyncResult syncUserIdWithVault(String userName, String password, Path idPath, String serverName) {
		checkDisposed();
		
		String userNameCanonical = NotesNamingUtils.toCanonicalName(userName);
		Memory userNameCanonicalMem = NotesStringUtils.toLMBCS(userNameCanonical, true);
		Memory passwordMem = NotesStringUtils.toLMBCS(password, true);
		Memory idPathMem = idPath==null ? null : NotesStringUtils.toLMBCS(idPath.toString(), true);
		Memory serverNameMem = new Memory(NotesConstants.MAXPATH);
		{
			Memory serverNameParamMem = NotesStringUtils.toLMBCS(serverName, true);
			if (serverNameParamMem!=null && (serverNameParamMem.size() > NotesConstants.MAXPATH)) {
				throw new IllegalArgumentException(MessageFormat.format("Servername length cannot exceed MAXPATH ({0} characters)", NotesConstants.MAXPATH));
			}
			if (serverNameParamMem!=null) {
				byte[] serverNameParamArr = serverNameParamMem.getByteArray(0, (int) serverNameParamMem.size());
				serverNameMem.write(0, serverNameParamArr, 0, serverNameParamArr.length);
			}
			else {
				serverNameMem.setByte(0, (byte) 0);
			}
		}
		
		PointerByReference phKFC = new PointerByReference();
		IntByReference retdwFlags = new IntByReference();
		
		short result = NotesCAPI.get().SECKFMOpen (phKFC, idPathMem, passwordMem, NotesConstants.SECKFM_open_All, 0, null);
		NotesErrorUtils.checkResult(result);
		
		try {
			result = NotesCAPI.get().SECidfSync(userNameCanonicalMem, passwordMem, idPathMem, phKFC, serverNameMem, 0, (short) 0, null, retdwFlags);
			NotesErrorUtils.checkResult(result);
		}
		finally {
			result = NotesCAPI.get().SECKFMClose(phKFC, NotesConstants.SECKFM_close_WriteIdFile, 0, null);
			NotesErrorUtils.checkResult(result);
		}
		
		int vaultServerNameLength = 0;
		for (int i=0; i T openUserIdFile(Path idPath, String password, IDAccessCallback callback) {
		checkDisposed();
		
		Memory idPathMem = idPath==null ? null : NotesStringUtils.toLMBCS(idPath.toString(), true);
		Memory passwordMem = NotesStringUtils.toLMBCS(password, true);
		
		//open the id file
		PointerByReference phKFC = new PointerByReference();
		
		short result = NotesCAPI.get().SECKFMOpen (phKFC, idPathMem, passwordMem, NotesConstants.SECKFM_open_All, 0, null);
		NotesErrorUtils.checkResult(result);
		
		JNAUserId id = null;
		try {
			id = new JNAUserId(this, new IAdaptable() {
				
				@SuppressWarnings("unchecked")
				@Override
				public  U getAdapter(Class clazz) {
					if (PointerByReference.class == clazz) {
						return (U) phKFC;
					}

					return null;
				}
			}, true);
			
			//invoke callback code
			return callback.accessId(id);
		}
		finally {
			//and close the ID file afterwards
			if (id!=null) {
				id.dispose();
			}
		}
	}

	@Override
	public boolean isIdInVault(String userName, String server) {
		checkDisposed();
		
		String serverCanonical = NotesNamingUtils.toCanonicalName(server);
		String usernameCanonical = NotesNamingUtils.toCanonicalName(userName);
		
		Memory serverCanonicalMem = NotesStringUtils.toLMBCS(serverCanonical, true);
		Memory usernameCanonicalMem = NotesStringUtils.toLMBCS(usernameCanonical, true);
		
		short result = NotesCAPI.get().SECidvIsIDInVault(serverCanonicalMem, usernameCanonicalMem);
		if ((result & NotesConstants.ERR_MASK) == 16372) {
			return false;
		}
		NotesErrorUtils.checkResult(result);

		return result == 0;
	}

	/**
	 * Internal helper method to fetch the ID from the ID vault.
	 * 
	 * @param userName Name of user whose ID is being put into vault - either abbreviated or canonical format
	 * @param password Password to id file being uploaded to the vault
	 * @param idPath if not null, path to where the download ID file should be created or overwritten
	 * @param rethKFC if not null, returns the hKFC handle to the in-memory id
	 * @param serverName Name of server to contact
	 * @return the vault server name
	 * @throws NotesError in case of problems, e.g. ERR 22792 Wrong Password
	 */
	private String _getUserIdFromVault(String userName, String password, Path idPath,
			PointerByReference rethKFC, String serverName) {
		
		String userNameCanonical = NotesNamingUtils.toCanonicalName(userName);
		Memory userNameCanonicalMem = NotesStringUtils.toLMBCS(userNameCanonical, true);
		Memory passwordMem = NotesStringUtils.toLMBCS(password, true);
		Memory idPathMem = idPath==null ? null : NotesStringUtils.toLMBCS(idPath.toString(), true);
		Memory serverNameMem = new Memory(NotesConstants.MAXPATH);
		{
			Memory serverNameParamMem = NotesStringUtils.toLMBCS(serverName, true);
			if (serverNameParamMem!=null && (serverNameParamMem.size() > NotesConstants.MAXPATH)) {
				throw new IllegalArgumentException(MessageFormat.format("Servername length cannot exceed MAXPATH ({0} characters)", NotesConstants.MAXPATH));
			}
			if (serverNameParamMem!=null) {
				byte[] serverNameParamArr = serverNameParamMem.getByteArray(0, (int) serverNameParamMem.size());
				serverNameMem.write(0, serverNameParamArr, 0, serverNameParamArr.length);
			}
			else {
				serverNameMem.setByte(0, (byte) 0);
			}
		}
		
		short result = NotesCAPI.get().SECidfGet(userNameCanonicalMem, passwordMem, idPathMem, rethKFC,
				serverNameMem, 0, (short) 0, null);
		NotesErrorUtils.checkResult(result);
		
		int vaultServerNameLength = 0;
		for (int i=0; iuserName,
	 * upload the ID file contents to the vault, then return with the vault server name.
* * @param userName Name of user whose ID is being put into vault - either abbreviated or canonical format * @param password Password to id file being uploaded to the vault * @param idPath Path to where the download ID file should be created or overwritten or null to use the in-memory id * @param phKFC handle to the in-memory id or null to use an id file on disk for 64 bit * @param serverName Name of server to contact * @return the vault server name * @throws NotesError in case of problems, e.g. ERR 22792 Wrong Password */ private String _putUserIdIntoVault(String userName, String password, Path idPath, PointerByReference phKFC, String serverName) { //opening any database on the server is required before putting the id fault, according to the //C API documentation and sample "idvault.c" String primaryDirectory = getParentDominoClient().openUserDirectory(serverName).getPrimaryDirectoryPath() .orElseThrow(() -> new IllegalStateException("Unable to identify primary directory path")); try (JNADatabase anyServerDb = new JNADatabase(getParentDominoClient(), serverName, primaryDirectory, EnumSet.noneOf(OpenDatabase.class));) { String userNameCanonical = NotesNamingUtils.toCanonicalName(userName); Memory userNameCanonicalMem = NotesStringUtils.toLMBCS(userNameCanonical, true); Memory passwordMem = NotesStringUtils.toLMBCS(password, true); Memory idPathMem = idPath==null ? null : NotesStringUtils.toLMBCS(idPath.toString(), true); Memory serverNameMem = new Memory(NotesConstants.MAXPATH); { Memory serverNameParamMem = NotesStringUtils.toLMBCS(serverName, true); if (serverNameParamMem!=null && (serverNameParamMem.size() > NotesConstants.MAXPATH)) { throw new IllegalArgumentException(MessageFormat.format("Servername length cannot exceed MAXPATH ({0} characters)", NotesConstants.MAXPATH)); } if (serverNameParamMem!=null) { byte[] serverNameParamArr = serverNameParamMem.getByteArray(0, (int) serverNameParamMem.size()); serverNameMem.write(0, serverNameParamArr, 0, serverNameParamArr.length); } else { serverNameMem.setByte(0, (byte) 0); } } short result = NotesCAPI.get().SECKFMOpen (phKFC, idPathMem, passwordMem, NotesConstants.SECKFM_open_All, 0, null); NotesErrorUtils.checkResult(result); try { result = NotesCAPI.get().SECidfPut(userNameCanonicalMem, passwordMem, idPathMem, phKFC, serverNameMem, 0, (short) 0, null); NotesErrorUtils.checkResult(result); } finally { result = NotesCAPI.get().SECKFMClose(phKFC, NotesConstants.SECKFM_close_WriteIdFile, 0, null); NotesErrorUtils.checkResult(result); } int vaultServerNameLength = 0; for (int i=0; i