/*
* ====================
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License("CDDL") (the "License"). You may not use this file
* except in compliance with the License.
*
* You can obtain a copy of the License at
* http://opensource.org/licenses/cddl1.php
* See the License for the specific language governing permissions and limitations
* under the License.
*
* When distributing the Covered Code, include this CDDL Header Notice in each file
* and include the License file at http://opensource.org/licenses/cddl1.php.
* If applicable, add the following below this CDDL Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
* ====================
*/
package org.identityconnectors.patternparser;
import static org.testng.Assert.assertEquals;
import java.io.StringReader;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.identityconnectors.patternparser.MapTransform.PatternNode;
import org.identityconnectors.patternparser.test.SubstringTransform;
import org.testng.annotations.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class PatternParserTest {
/* @formatter:off */
static final String PATTERN =
"<MapTransform>\n" +
" <PatternNode key='username' pattern='Username:\\s+(.*?)\\s*(?=Owner)' optional='false' reset='false'/>\n" +
" <PatternNode key='owner' pattern='Owner:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='account' pattern='Account:\\s+(.*?)\\s*(?=UIC)' optional='false' reset='false'/>\n" +
" <PatternNode key='uic' pattern='UIC:\\s+(\\[[^]]+\\]).*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='cli' pattern='CLI:\\s+(.*?)\\s*(?=Tables)' optional='false' reset='false'/>\n" +
" <PatternNode key='clitables' pattern='Tables:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='default' pattern='Default:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='lgicmd' pattern='LGICMD:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='Flags' pattern='Flags:\\s+(.*?)\\s*(?=Primary days)' optional='false' reset='false'>\n" +
" <SplitTransform splitPattern='\\s+'/>\n" +
" </PatternNode>\n" +
" <PatternNode key='Primary days' pattern='Primary days:\\s+(.*?)\\s*\\n' optional='false' reset='false'>\n" +
" <SplitTransform splitPattern='\\s+'/>\n" +
" </PatternNode>\n" +
" <PatternNode key='Secondary days' pattern='Secondary days:\\s+(.*?)\\s*\\n' optional='false' reset='false'>\n" +
" <SplitTransform splitPattern='\\s+'/>\n" +
" </PatternNode>\n" +
" <PatternNode key='expiration' pattern='Expiration:\\s+(.*?)\\s*(?=Pwdminimum)' optional='false' reset='false'/>\n" +
" <PatternNode key='pwdminimum' pattern='Pwdminimum:\\s+(.*?)\\s*(?=Login Fails)' optional='false' reset='false'/>\n" +
" <PatternNode key='loginfails' pattern='Login Fails:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='pwdlifetime' pattern='Pwdlifetime:\\s+(.*?)\\s*(?=Pwdchange)' optional='false' reset='false'/>\n" +
" <PatternNode key='pwdchange' pattern='Pwdchange:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='lastlogin' pattern='Last Login:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='maxjobs' pattern='Maxjobs:\\s+(.*?)\\s*(?=Fillm)' optional='false' reset='false'/>\n" +
" <PatternNode key='fillm' pattern='Fillm:\\s+(.*?)\\s*(?=Bytlm)' optional='false' reset='false'/>\n" +
" <PatternNode key='bytlm' pattern='Bytlm:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='maxacctjobs' pattern='Maxacctjobs:\\s+(.*?)\\s*(?=Shrfillm)' optional='false' reset='false'/>\n" +
" <PatternNode key='shrfillm' pattern='Shrfillm:\\s+(.*?)\\s*(?=Pbytlm)' optional='false' reset='false'/>\n" +
" <PatternNode key='pbytlm' pattern='Pbytlm:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='maxdetach' pattern='Maxdetach:\\s+(.*?)\\s*(?=BIOlm)' optional='false' reset='false'/>\n" +
" <PatternNode key='biolm' pattern='BIOlm:\\s+(.*?)\\s*(?=JTquota)' optional='false' reset='false'/>\n" +
" <PatternNode key='jtquota' pattern='JTquota:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='prclm' pattern='Prclm:\\s+(.*?)\\s*(?=DIOlm)' optional='false' reset='false'/>\n" +
" <PatternNode key='diolm' pattern='DIOlm:\\s+(.*?)\\s*(?=WSdef)' optional='false' reset='false'/>\n" +
" <PatternNode key='wsdef' pattern='WSdef:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='prio' pattern='Prio:\\s+(.*?)\\s*(?=ASTlm)' optional='false' reset='false'/>\n" +
" <PatternNode key='astlm' pattern='ASTlm:\\s+(.*?)\\s*(?=WSquo)' optional='false' reset='false'/>\n" +
" <PatternNode key='wsquo' pattern='WSquo:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='queprio' pattern='Queprio:\\s+(.*?)\\s*(?=TQElm)' optional='false' reset='false'/>\n" +
" <PatternNode key='tqelm' pattern='TQElm:\\s+(.*?)\\s*(?=WSextent)' optional='false' reset='false'/>\n" +
" <PatternNode key='wsextent' pattern='WSextent:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='cpu' pattern='CPU:\\s+(.*?)\\s*(?=Enqlm)' optional='false' reset='false'/>\n" +
" <PatternNode key='enqlm' pattern='Enqlm:\\s+(.*?)\\s*(?=Pgflquo)' optional='false' reset='false'/>\n" +
" <PatternNode key='pgflquo' pattern='Pgflquo:\\s+(.*?)\\s*\\n' optional='false' reset='false'/>\n" +
" <PatternNode key='Authorized Privileges' pattern='Authorized Privileges:\\s+\\n\\s{2}?((?:.+\\n)(?:\\s{2}.+\\n)*)' optional='false' reset='false'>\n" +
" <SubstituteTransform pattern='IMPERSONAT(\\w\\w+)' substitute='IMPERSONATE $1'/>\n" +
" <SplitTransform splitPattern='\\s+'/>\n" +
" </PatternNode>\n" +
" <PatternNode key='Default Privileges' pattern='Default Privileges:\\s+\\n\\s{2}?((?:.+\\n)(?:\\s{2}.+\\n)*)' optional='false' reset='false'>\n" +
" <SubstituteTransform pattern='IMPERSONAT(\\w\\w+)' substitute='IMPERSONATE $1'/>\n" +
" <SplitTransform splitPattern='\\s+'/>\n" +
" </PatternNode>\n" +
" <PatternNode key='Identifier' pattern='Identifier.*?\\n\\s{2}?((?:.+\\n)(?:\\s{2}.+\\n)*)' optional='false' reset='false'>\n" +
" <SplitTransform splitPattern='\\n'/>\n" +
" <ListTransform>\n" +
" <GroupsTransform mapPattern='\\s*(\\S+)\\s+(\\S+)\\s*(\\S+)?$'/>\n" +
" </ListTransform>\n" +
" </PatternNode>\n" +
"</MapTransform>\n";
static final String SAMPLE_USER =
"Username: SYSTEM Owner: SYSTEM MANAGER\n" +
"Account: SYSTEM UIC: [1,4] ([SYSTEM])\n" +
"CLI: DCL Tables: DCLTABLES\n" +
"Default: SYS$SYSROOT:[SYSMGR]\n" +
"LGICMD: LOGIN\n" +
"Flags: \n" +
"Primary days: Mon Tue Wed Thu Fri \n" +
"Secondary days: Sat Sun\n" +
"No access restrictions\n" +
"Expiration: (none) Pwdminimum: 8 Login Fails: 0\n" +
"Pwdlifetime: (none) Pwdchange: 21-JUL-2005 16:28 \n" +
"Last Login: 29-OCT-2007 00:19 (interactive), 28-JUN-2007 15:23 (non-interactive)\n" +
"Maxjobs: 0 Fillm: 300 Bytlm: 32768\n" +
"Maxacctjobs: 0 Shrfillm: 0 Pbytlm: 0\n" +
"Maxdetach: 0 BIOlm: 40 JTquota: 4096\n" +
"Prclm: 10 DIOlm: 40 WSdef: 256\n" +
"Prio: 4 ASTlm: 50 WSquo: 512\n" +
"Queprio: 0 TQElm: 30 WSextent: 2048\n" +
"CPU: (none) Enqlm: 200 Pgflquo: 40960\n" +
"Authorized Privileges: \n" +
" ACNT ALLSPOOL ALTPRI AUDIT BUGCHK BYPASS CMEXEC CMKRNL\n" +
" IMPERSONATDIAGNOSE DOWNGRADE EXQUOTA GROUP GRPNAM GRPPRV IMPORT\n" +
" LOG_IO MOUNT NETMBX OPER PFNMAP PHY_IO PRMCEB PRMGBL\n" +
" PRMMBX PSWAPM READALL SECURITY SETPRV SHARE SHMEM SYSGBL\n" +
" SYSLCK SYSNAM SYSPRV TMPMBX UPGRADE VOLPRO WORLD\n" +
"Default Privileges: \n" +
" ACNT ALLSPOOL ALTPRI AUDIT BUGCHK BYPASS CMEXEC CMKRNL\n" +
" IMPERSONATDIAGNOSE DOWNGRADE EXQUOTA GROUP GRPNAM GRPPRV IMPORT\n" +
" LOG_IO MOUNT NETMBX OPER PFNMAP PHY_IO PRMCEB PRMGBL\n" +
" PRMMBX PSWAPM READALL SECURITY SETPRV SHARE SHMEM SYSGBL\n" +
" SYSLCK SYSNAM SYSPRV TMPMBX UPGRADE VOLPRO WORLD\n" +
"Identifier Value Attributes\n" +
" GOOMBAH %X91F50002 Zoom\n" +
" NET$MANAGE %X91F5AAAA \n"
;
/* @formatter:on */
/**
* Parse a string from AUTHORIZE and return a Map containing the user data
*
* @param user
* -- string output from AUTHORIZE describing a user
* @return Map<String, Object> -- map describing user attributes
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static Map<String, Object> parseAuthorizeOutput(String user) throws Exception {
Map<String, Object> userMap = mapTransform.transform(user);
return userMap;
}
public static MapTransform mapTransform = null;
@Test
public void testWithPatterns() throws Exception {
mapTransform = (MapTransform) getTransform(PATTERN);
Map<String, Object> userMap = parseAuthorizeOutput(SAMPLE_USER);
System.out.println(userMap);
}
@Test
public void testBooleanTransform() throws Exception {
Transform transform = new BooleanTransform();
assertEquals(transform.transform("true"), Boolean.TRUE);
assertEquals(transform.transform("True"), Boolean.TRUE);
assertEquals(transform.transform("TRUE"), Boolean.TRUE);
assertEquals(transform.transform("false"), Boolean.FALSE);
assertEquals(transform.transform("False"), Boolean.FALSE);
assertEquals(transform.transform("FALSE"), Boolean.FALSE);
assertEquals(transform.transform("Hi"), "Hi");
}
@Test
public void testClassTransform() throws Exception {
Transform transform = new ClassTransform(SampleTransform.class);
SampleTransform test = (SampleTransform) transform.transform("Okay");
assertEquals(test.getData(), "Okay");
String xml = transform.toXml(0);
transform = getTransform(xml);
test = (SampleTransform) transform.transform("Okay");
assertEquals(test.getData(), "Okay");
test = (SampleTransform) transform.transform("Okay");
assertEquals(test.getData(), "Okay");
}
public static class SampleTransform {
private String data;
public SampleTransform(String data) {
this.data = data;
}
public String getData() {
return data;
}
};
@Test
public void testTransformSubtype() throws Exception {
Transform transform = new SubstringTransform(1, 3);
String string = transform.toXml(0);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
DocumentBuilder parser = factory.newDocumentBuilder();
Document document = parser.parse(new InputSource(new StringReader(string)));
NodeList elements = document.getChildNodes();
Transform newTransform = Transform.newTransform((Element) elements.item(0));
assertEquals(newTransform.transform("abcde"), "bc");
}
@Test
public void testPatternFormatting() throws Exception {
mapTransform = (MapTransform) getTransform(PATTERN);
String formatted = mapTransform.toXml(0);
assertEquals(formatted, PATTERN);
formatted = mapTransform.toXml(2);
assertEquals(formatted.replaceAll("\n ", "\n").substring(2), PATTERN);
}
@Test
public void testDumpRacf() throws Exception {
Transform transform = new MapTransform(RacfInfo.PARSER);
String xml = new MapTransform(RacfInfo.PARSER).toXml(0);
transform = Transform.newTransform(xml);
System.out.println(xml);
}
private static Transform getTransform(String string) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
DocumentBuilder parser = factory.newDocumentBuilder();
Document document = parser.parse(new InputSource(new StringReader(string)));
NodeList elements = document.getChildNodes();
for (int i = 0; i < elements.getLength(); i++)
if (elements.item(i) instanceof Element) {
return Transform.newTransform((Element) elements.item(i));
}
return null;
}
// ???
/**
* This class is used to generate several alternate versions of a RACF
* output parser.
*/
public static class RacfInfo {
private static final List<PatternNode> PARSER = new LinkedList<PatternNode>();
static {
try {
PARSER.add(new PatternNode("USERID", "USER=(\\w{1,8})"));
PARSER.add(new PatternNode("NAME", "NAME=(.*?)\\s+(?=OWNER=)"));
PARSER.add(new PatternNode("OWNER", "OWNER=(\\w{1,8})", false, false,
new Transform[] { new SubstituteTransform("^$", "UNKNOWN"), }));
PARSER.add(new PatternNode("DFLTGRP", "DEFAULT-GROUP=(\\w{1,8})"));
PARSER.add(new PatternNode("PASSDATE", "PASSDATE=(\\S{0,6})"));
PARSER.add(new PatternNode("PASSWORD INTERVAL", "PASS-INTERVAL=(\\S*)"));
PARSER.add(new PatternNode("PHRASEDATE", "PHRASEDATE=(.*?)\\s+\\n", true,
false, null));
PARSER.add(new PatternNode("ATTRIBUTES", "((ATTRIBUTES=.*\\n\\s*)+)", true,
false, new Transform[] { new SubstituteTransform("ATTRIBUTES=(\\S+)\\s+", "$1 "),
new SubstituteTransform("(.*)\\s", "$1"),
new SubstituteTransform("^$", "NONE"), new SplitTransform("\\s"), }));
PARSER.add(new PatternNode("CLAUTH",
"CLASS AUTHORIZATIONS=([^\\n]*(\\s{23}.+\\n)*)", true, false,
new Transform[] { new SubstituteTransform("(.*)\\s", "$1"),
new SplitTransform("\\s+"), }));
PARSER.add(new PatternNode("DATA", "INSTALLATION-DATA=([^\\n]*(\\s{20}.+\\n)*)",
true, false, new Transform[] {
new SubstituteTransform("^(.{50})[^\\n]+", "$1"),
new SubstituteTransform("\\n\\s{20}(.{50})[^\\n]+", "$1"),
new SubstituteTransform("\\n", ""),
new SubstituteTransform("^$", "NO-INSTALLATION-DATA"), }));
PARSER.add(new PatternNode("RACF.GROUPS",
"((\\s+GROUP=\\w+\\s+AUTH=.+?CONNECT-OWNER=([^\\n]+\\n){4})+)", true,
false, new Transform[] {
new SubstituteTransform(
".*?GROUP=(\\w+)\\s+AUTH=.+?CONNECT-OWNER=\\w+([^\\n]+\\n){4}",
"$1 "), new SplitTransform("\\s+"), }));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}