/*
* � Copyright IBM Corp. 2013
*
* 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:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.ibm.domino.das.resources;
import static com.ibm.domino.das.service.CoreService.PATH_SEGMENT_CORE;
import static com.ibm.domino.das.service.CoreService.PATH_SEGMENT_PW_STATS;
import java.io.IOException;
import java.util.Date;
import java.util.Vector;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import lotus.domino.DateTime;
import lotus.domino.Directory;
import lotus.domino.DirectoryNavigator;
import lotus.domino.Document;
import lotus.domino.Name;
import lotus.domino.NotesException;
import lotus.domino.Session;
import com.ibm.commons.util.io.json.JsonException;
import com.ibm.commons.util.io.json.JsonGenerator;
import com.ibm.commons.util.io.json.JsonGenerator.StringBuilderGenerator;
import com.ibm.commons.util.io.json.JsonJavaFactory;
import com.ibm.commons.util.io.json.JsonJavaObject;
import com.ibm.domino.commons.json.JsonConstants;
import com.ibm.domino.commons.util.BackendUtil;
import com.ibm.domino.das.service.CoreService;
import com.ibm.domino.osgi.core.context.ContextInfo;
@Path(PATH_SEGMENT_CORE + "/" + PATH_SEGMENT_PW_STATS)
public class PasswordStatisticsResource {
private static final String JSON_CHANGE_INTERVAL = "changeinterval"; // $NON-NLS-1$
private static final String JSON_INTERNET_PASSWORD = "internetpassword"; // $NON-NLS-1$
private static final String JSON_NOTES_PASSWORD = "notespassword"; // $NON-NLS-1$
private static final String JSON_EXPIRE_DATE = "expiredate"; // $NON-NLS-1$
private static final String JSON_CHANGE_DATE = "lastchangedate"; // $NON-NLS-1$
private static final String JSON_EXPIRES = "expires"; // $NON-NLS-1$
private static final String JSON_SYNC_WITH_NOTES = "syncwithnotes"; // $NON-NLS-1$
private static final String JSON_CHANGE_OVER_HTTP = "changeoverhttp"; // $NON-NLS-1$
private static final int PD_CHANGE_INTERVAL = 0;
private static final int PD_NOTES_CHANGE_DATE = 1;
private static final int PD_INTERNET_CHANGE_DATE = 2;
private Vector<String> s_lookupItems = lookupItems();
private long ONE_DAY = 1000L * 60 * 60 * 24;
/**
* Gets password statistics (change date, expire date, etc.)
*
* @return
*/
@GET
public Response getPassword() {
String jsonEntity = null;
CoreService.verifyUserContext();
try {
Session session = ContextInfo.getUserSession();
// Get the password stats
JsonJavaObject obj = getPasswordStats(session);
// Serialize the JSON
StringBuilder sb = new StringBuilder();
JsonGenerator.Generator generator = new StringBuilderGenerator(JsonJavaFactory.instanceEx, sb, false);
generator.toJson(obj);
jsonEntity = sb.toString();
}
catch (NotesException e) {
throw new WebApplicationException(CoreService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
catch (JsonException e) {
throw new WebApplicationException(CoreService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
catch (IOException e) {
throw new WebApplicationException(CoreService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
ResponseBuilder builder = Response.ok();
if ( jsonEntity != null ) {
builder.type(MediaType.APPLICATION_JSON_TYPE).entity(jsonEntity);
}
Response response = builder.build();
return response;
}
/**
* Internal implementation of password statistics.
*
* <p>TODO: Move this to com.ibm.domino.commons.model.
*
* @param session
* @return
* @throws NotesException
*/
private JsonJavaObject getPasswordStats(Session session) throws NotesException {
JsonJavaObject obj = null;
Document document = null;
try {
boolean notesPwdExpires = false;
boolean internetPwdExpires = false;
boolean internetPwdSync = false;
boolean internetPwdChangeHttp = true; // Default is true
int changeInterval = -1;
// Get the effective user's name
String user = session.getEffectiveUserName();
Name name = session.createName(user);
// Get the password data from the person record
Object personData[] = getPersonRecordData(session, user);
// Get the security policy for this user
Vector values = null;
document = session.getUserPolicySettings("", name.getAbbreviated(), Session.POLICYSETTINGS_SECURITY);
if ( document == null ) {
// There is no policy. Use settings from person doc.
//
// Note these assumptions: 1) The person doc only affects Notes password expiration
// (not internet passwords), and 2) the Notes password expires only if the CheckPassword
// item == "1" and the password change interval > 0.
if ( personData != null && personData[PD_CHANGE_INTERVAL] != null ) {
changeInterval = (Integer)personData[PD_CHANGE_INTERVAL];
if ( changeInterval > 0 ) {
notesPwdExpires = true;
}
}
}
else {
// Get the expiration policy
values = document.getItemValue("PwdExp"); // $NON-NLS-1$
if ( values != null && values.size() > 0 && values.get(0) instanceof String ) {
String strValue = (String)values.get(0);
if ( "1".equals(strValue) ) {
notesPwdExpires = true;
}
else if ( "2".equals(strValue) ) {
internetPwdExpires = true;
}
else if ( "3".equals(strValue) ) {
notesPwdExpires = true;
internetPwdExpires = true;
}
}
// Get the change interval
if ( notesPwdExpires || internetPwdExpires ) {
values = document.getItemValue("PasswordChangeInterval"); // $NON-NLS-1$
if ( values != null && values.size() > 0 && values.get(0) instanceof Double) {
Double dValue = (Double)values.get(0);
changeInterval = dValue.intValue();
}
}
// Get the other internet password settings
values = document.getItemValue("PwdSync"); // $NON-NLS-1$
if ( values != null && values.size() > 0 && values.get(0) instanceof String) {
String strValue = (String)values.get(0);
if ( "1".equals(strValue) ) {
internetPwdSync = true;
}
}
values = document.getItemValue("PwdAlwHTTP"); // $NON-NLS-1$
if ( values != null && values.size() > 0 && values.get(0) instanceof String) {
String strValue = (String)values.get(0);
if ( "0".equals(strValue) ) {
internetPwdChangeHttp = false;
}
}
}
// Create the JSON object
obj = new JsonJavaObject();
JsonJavaObject notes = new JsonJavaObject();
notes.putBoolean(JSON_EXPIRES, notesPwdExpires);
if ( personData != null && personData[PD_NOTES_CHANGE_DATE] != null ) {
Date date = (Date)personData[PD_NOTES_CHANGE_DATE];
notes.putString(JSON_CHANGE_DATE, JsonConstants.ISO8601_UTC.format(date));
if ( notesPwdExpires && changeInterval > 0 ) {
Date expireDate = new Date(date.getTime() + (ONE_DAY*changeInterval));
notes.putString(JSON_EXPIRE_DATE, JsonConstants.ISO8601_UTC.format(expireDate));
}
}
obj.putObject(JSON_NOTES_PASSWORD, notes);
JsonJavaObject internet = new JsonJavaObject();
internet.putBoolean(JSON_EXPIRES, internetPwdExpires);
if ( personData != null && personData[PD_INTERNET_CHANGE_DATE] != null ) {
Date date = (Date)personData[PD_INTERNET_CHANGE_DATE];
internet.putString(JSON_CHANGE_DATE, JsonConstants.ISO8601_UTC.format(date));
internet.putBoolean(JSON_SYNC_WITH_NOTES, internetPwdSync);
internet.putBoolean(JSON_CHANGE_OVER_HTTP, internetPwdChangeHttp);
if ( internetPwdExpires && changeInterval > 0 ) {
Date expireDate = new Date(date.getTime() + (ONE_DAY*changeInterval));
internet.putString(JSON_EXPIRE_DATE, JsonConstants.ISO8601_UTC.format(expireDate));
}
}
obj.putObject(JSON_INTERNET_PASSWORD, internet);
if ( changeInterval > 0 ) {
obj.putInt(JSON_CHANGE_INTERVAL, changeInterval);
}
}
finally {
BackendUtil.safeRecycle(document);
}
return obj;
}
private static Vector<String> lookupItems() {
Vector<String> lookupItems = new Vector<String>();
lookupItems.addElement("FullName"); //$NON-NLS-1$
lookupItems.addElement("ShortName"); //$NON-NLS-1$
lookupItems.addElement("CheckPassword"); //$NON-NLS-1$
lookupItems.addElement("PasswordChangeInterval"); //$NON-NLS-1$
lookupItems.addElement("PasswordChangeDate"); //$NON-NLS-1$
lookupItems.addElement("HTTPPasswordChangeDate"); //$NON-NLS-1$
return lookupItems;
}
/**
* Gets the last change dates from the person record.
*
* @param session
* @param canonicalName
* @return
* @throws NotesException
*/
private Object[] getPersonRecordData(Session session, String canonicalName) throws NotesException {
Object personData[] = null;
Directory lookupDir = null;
try {
// Find the user
DirectoryNavigator dirNav = null;
lookupDir = session.getDirectory();
if ( lookupDir != null ) {
Vector<String> vName = new Vector<String>();
vName.addElement(canonicalName);
dirNav = lookupDir.lookupNames("($Users)", vName, s_lookupItems, true); //$NON-NLS-1$
}
// Digest the results of the lookup
Integer changeInterval = -1;
DateTime notesChangeDate = null;
DateTime internetChangeDate = null;
if( dirNav != null && dirNav.getCurrentMatches() != 0 ){
Vector value = null;
value = dirNav.getFirstItemValue();
String fullName = (String)value.elementAt(0);
value = dirNav.getNextItemValue();
String shortName = (String)value.elementAt(0);
value = dirNav.getNextItemValue();
String checkPassword = null;
if ( value != null && value.size() > 0 && value.elementAt(0) instanceof String ) {
checkPassword = (String)value.elementAt(0);
}
value = dirNav.getNextItemValue();
if ( "1".equals(checkPassword) && value != null && value.size() > 0 && value.elementAt(0) instanceof Double ) {
changeInterval = ((Double)value.elementAt(0)).intValue();
}
value = dirNav.getNextItemValue();
if ( value != null && value.size() > 0 && value.elementAt(0) instanceof DateTime ) {
notesChangeDate = (DateTime)value.elementAt(0);
}
value = dirNav.getNextItemValue();
if ( value != null && value.size() > 0 && value.elementAt(0) instanceof DateTime ) {
internetChangeDate = (DateTime)value.elementAt(0);
}
}
// Create the return array
if ( changeInterval > 0 || notesChangeDate != null || internetChangeDate != null ) {
personData = new Object[3];
if ( changeInterval != -1 ) {
personData[PD_CHANGE_INTERVAL] = changeInterval;
}
if ( notesChangeDate != null ) {
personData[PD_NOTES_CHANGE_DATE] = notesChangeDate.toJavaDate();
}
if ( internetChangeDate != null ) {
personData[PD_INTERNET_CHANGE_DATE] = internetChangeDate.toJavaDate();
}
}
}
finally {
BackendUtil.safeRecycle(lookupDir);
}
return personData;
}
}