List of usage examples for java.util TreeSet iterator
public Iterator<E> iterator()
From source file:edu.umass.cs.gigapaxos.SQLPaxosLogger.java
private static Set<Filename> getAllButLatest(File[] files, int keep) { TreeSet<Filename> allFiles = new TreeSet<Filename>(); TreeSet<Filename> oldFiles = new TreeSet<Filename>(); for (File file : files) allFiles.add(new Filename(file)); if (allFiles.size() <= keep) return oldFiles; Iterator<Filename> iter = allFiles.iterator(); for (int i = 0; i < allFiles.size() - keep; i++) oldFiles.add(iter.next());/*w w w.jav a2 s. co m*/ return oldFiles; }
From source file:org.apache.myfaces.trinidadbuild.plugin.tagdoc.TagdocReport.java
private void _writeAccessibilityGuidelines(Writer out, ComponentBean bean) throws IOException { // accAttributes and accFacets are sorted lists of attributes and facets, respectively, // that have an associated accessibility guideline TreeSet<PropertyBean> accAttributes = new TreeSet<PropertyBean>(); TreeSet<String> accFacets = new TreeSet<String>(); // see if any of the component's properties has an associated accessibility guideline Iterator<PropertyBean> attrs = bean.properties(); while (attrs.hasNext()) { PropertyBean property = attrs.next(); if (!property.isTagAttributeExcluded() && property.hasAccessibilityGuidelines()) { accAttributes.add(property); }/*from w w w .ja v a 2 s . com*/ } // see if any of the component's facets has an associated accessibility guideline if (bean.hasFacets()) { Iterator<FacetBean> facets = bean.facets(true); while (facets.hasNext()) { FacetBean facetBean = facets.next(); if (!facetBean.isHidden() && facetBean.hasAccessibilityGuidelines()) { accFacets.add(facetBean.getFacetName()); } } } // if neither the component nor the component's attributes nor the component's facets // has an accessibility guideline, return if (!bean.hasAccessibilityGuidelines() && accAttributes.isEmpty() && accFacets.isEmpty()) return; String accGuideline; // Write header out.write(" <section name=\"Accessibility Guideline(s)\">\n"); out.write(" <p>\n"); out.write(" <html>\n"); out.write(" <ul>"); // write out component-generic accessibility guidelines, i.e. accessibility // guidelines that apply to the component as a whole, not associated with a // specific attribute if (bean.hasAccessibilityGuidelines()) { Iterator<String> iter = bean.accessibilityGuidelines(); while (iter.hasNext()) { accGuideline = iter.next(); _writeAccessibilityGuideline(out, "", accGuideline); } } // Write out attribute-specific accessibility guidelines. Each attribute can have // one or more associated accessibility guidelines. if (!accAttributes.isEmpty()) { Iterator<PropertyBean> propIter = accAttributes.iterator(); while (propIter.hasNext()) { PropertyBean property = propIter.next(); Iterator<String> propAccIter = property.accessibilityGuidelines(); while (propAccIter.hasNext()) { accGuideline = propAccIter.next(); _writeAccessibilityGuideline(out, property.getPropertyName() + " attribute", accGuideline); } } } // Write out facet-specific accessibility guidelines. A facet in the accFacets iterator // can have one or more associated accessibility guidelines if (!accFacets.isEmpty()) { Iterator<String> facetIter = accFacets.iterator(); while (facetIter.hasNext()) { String facetName = facetIter.next(); FacetBean facet = bean.findFacet(facetName, true); Iterator<String> facetAccIter = facet.accessibilityGuidelines(); while (facetAccIter.hasNext()) { accGuideline = facetAccIter.next(); _writeAccessibilityGuideline(out, facetName + " facet", accGuideline); } } } out.write(" </ul>"); out.write(" </html>\n"); out.write(" </p>\n"); out.write(" </section>\n"); }
From source file:org.chiba.tools.schemabuilder.AbstractSchemaFormBuilder.java
/** * add an element to the XForms document: the bind + the control * (only the control if "withBind" is false) */// w w w . j a v a 2 s . c o m private void addElement(Document xForm, Element modelSection, Element formSection, XSElementDeclaration elementDecl, XSTypeDefinition controlType, String pathToRoot) { if (controlType == null) { // TODO!!! Figure out why this happens... for now just warn... // seems to happen when there is an element of type IDREFS LOGGER.warn("WARNING!!! controlType is null for " + elementDecl + ", " + elementDecl.getName()); return; } switch (controlType.getTypeCategory()) { case XSTypeDefinition.SIMPLE_TYPE: { addSimpleType(xForm, modelSection, formSection, (XSSimpleTypeDefinition) controlType, elementDecl, pathToRoot); break; } case XSTypeDefinition.COMPLEX_TYPE: { if (controlType.getName() != null && controlType.getName().equals("anyType")) { addAnyType(xForm, modelSection, formSection, (XSComplexTypeDefinition) controlType, elementDecl, pathToRoot); break; } else { // find the types which are compatible(derived from) the parent type. // // This is used if we encounter a XML Schema that permits the xsi:type // attribute to specify subtypes for the element. // // For example, the <address> element may be typed to permit any of // the following scenarios: // <address xsi:type="USAddress"> // </address> // <address xsi:type="CanadianAddress"> // </address> // <address xsi:type="InternationalAddress"> // </address> // // What we want to do is generate an XForm' switch element with cases // representing any valid non-abstract subtype. // // <xforms:select1 xforms:bind="xsi_type_13" // <xforms:label>Address</xforms:label> // <xforms:choices> // <xforms:item> // <xforms:label>US Address Type</xforms:label> // <xforms:value>USAddressType</xforms:value> // <xforms:action ev:event="xforms-select"> // <xforms:toggle xforms:case="USAddressType-case"/> // </xforms:action> // </xforms:item> // <xforms:item> // <xforms:label>Canadian Address Type</xforms:label> // <xforms:value>CanadianAddressType</xforms:value> // <xforms:action ev:event="xforms-select"> // <xforms:toggle xforms:case="CanadianAddressType-case"/> // </xforms:action> // </xforms:item> // <xforms:item> // <xforms:label>International Address Type</xforms:label> // <xforms:value>InternationalAddressType</xforms:value> // <xforms:action ev:event="xforms-select"> // <xforms:toggle xforms:case="InternationalAddressType-case"/> // </xforms:action> // </xforms:item> // // </xforms:choices> // <xforms:select1> // <xforms:trigger> // <xforms:label>validate Address type</xforms:label> // <xforms:action> // <xforms:dispatch id="dispatcher" xforms:name="xforms-activate" xforms:target="select1_0"/> // </xforms:action> //</xforms:trigger> // // <xforms:switch id="address_xsi_type_switch"> // <xforms:case id="USAddressType-case" selected="false"> // <!-- US Address Type sub-elements here--> // </xforms:case> // <xforms:case id="CanadianAddressType-case" selected="false"> // <!-- US Address Type sub-elements here--> // </xforms:case> // ... // </xforms:switch> // // + change bindings to add: // - a bind for the "@xsi:type" attribute // - for each possible element that can be added through the use of an inheritance, add a "relevant" attribute: // ex: xforms:relevant="../@xsi:type='USAddress'" // look for compatible types // String typeName = controlType.getName(); boolean relative = true; if (typeName != null) { TreeSet compatibleTypes = (TreeSet) typeTree.get(controlType.getName()); //TreeSet compatibleTypes = (TreeSet) typeTree.get(controlType); if (compatibleTypes != null) { relative = false; if (LOGGER.isDebugEnabled()) { LOGGER.debug("compatible types for " + typeName + ":"); Iterator it1 = compatibleTypes.iterator(); while (it1.hasNext()) { //String name = (String) it1.next(); XSTypeDefinition compType = (XSTypeDefinition) it1.next(); LOGGER.debug(" compatible type name=" + compType.getName()); } } Element control = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "select1"); String select1_id = this.setXFormsId(control); Element choices = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "choices"); this.setXFormsId(choices); //get possible values Vector enumValues = new Vector(); //add the type (if not abstract) if (!((XSComplexTypeDefinition) controlType).getAbstract()) enumValues.add(controlType); //enumValues.add(typeName); //add compatible types Iterator it = compatibleTypes.iterator(); while (it.hasNext()) { enumValues.add(it.next()); } if (enumValues.size() > 1) { String caption = createCaption(elementDecl.getName() + " Type"); Element controlCaption = (Element) control .appendChild(xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "label")); this.setXFormsId(controlCaption); controlCaption.appendChild(xForm.createTextNode(caption)); // multiple compatible types for this element exist // in the schema - allow the user to choose from // between compatible non-abstract types Element bindElement = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "bind"); String bindId = this.setXFormsId(bindElement); bindElement.setAttributeNS(XFORMS_NS, getXFormsNSPrefix() + "nodeset", pathToRoot + "/@xsi:type"); modelSection.appendChild(bindElement); control.setAttributeNS(XFORMS_NS, getXFormsNSPrefix() + "bind", bindId); //add the "element" bind, in addition Element bindElement2 = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "bind"); String bindId2 = this.setXFormsId(bindElement2); bindElement2.setAttributeNS(XFORMS_NS, getXFormsNSPrefix() + "nodeset", pathToRoot); modelSection.appendChild(bindElement2); if (enumValues.size() < Long.parseLong(getProperty(SELECTONE_LONG_LIST_SIZE_PROP))) { control.setAttributeNS(XFORMS_NS, getXFormsNSPrefix() + "appearance", getProperty(SELECTONE_UI_CONTROL_SHORT_PROP)); } else { control.setAttributeNS(XFORMS_NS, getXFormsNSPrefix() + "appearance", getProperty(SELECTONE_UI_CONTROL_LONG_PROP)); // add the "Please select..." instruction item for the combobox // and set the isValid attribute on the bind element to check for the "Please select..." // item to indicate that is not a valid value // String pleaseSelect = "[Select1 " + caption + "]"; Element item = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "item"); this.setXFormsId(item); choices.appendChild(item); Element captionElement = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "label"); this.setXFormsId(captionElement); item.appendChild(captionElement); captionElement.appendChild(xForm.createTextNode(pleaseSelect)); Element value = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "value"); this.setXFormsId(value); item.appendChild(value); value.appendChild(xForm.createTextNode(pleaseSelect)); // not(purchaseOrder/state = '[Choose State]') //String isValidExpr = "not(" + bindElement.getAttributeNS(XFORMS_NS, "nodeset") + " = '" + pleaseSelect + "')"; // ->no, not(. = '[Choose State]') String isValidExpr = "not( . = '" + pleaseSelect + "')"; //check if there was a constraint String constraint = bindElement.getAttributeNS(XFORMS_NS, "constraint"); if ((constraint != null) && !constraint.equals("")) { constraint = constraint + " && " + isValidExpr; } else { constraint = isValidExpr; } bindElement.setAttributeNS(XFORMS_NS, getXFormsNSPrefix() + "constraint", constraint); } Element choicesControlWrapper = _wrapper.createControlsWrapper(choices); control.appendChild(choicesControlWrapper); Element controlWrapper = _wrapper.createControlsWrapper(control); formSection.appendChild(controlWrapper); ///////////////// /////////////// // add content to select1 HashMap case_types = new HashMap(); addChoicesForSelectSwitchControl(xForm, choices, enumValues, case_types); ///////////////// //add a trigger for this control (is there a way to not need it ?) Element trigger = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "trigger"); formSection.appendChild(trigger); this.setXFormsId(trigger); Element label_trigger = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "label"); this.setXFormsId(label_trigger); trigger.appendChild(label_trigger); String trigger_caption = createCaption("validate choice"); label_trigger.appendChild(xForm.createTextNode(trigger_caption)); Element action_trigger = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "action"); this.setXFormsId(action_trigger); trigger.appendChild(action_trigger); Element dispatch_trigger = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "dispatch"); this.setXFormsId(dispatch_trigger); action_trigger.appendChild(dispatch_trigger); dispatch_trigger.setAttributeNS(XFORMS_NS, getXFormsNSPrefix() + "name", "DOMActivate"); dispatch_trigger.setAttributeNS(XFORMS_NS, getXFormsNSPrefix() + "target", select1_id); ///////////////// //add switch Element switchElement = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "switch"); this.setXFormsId(switchElement); Element switchControlWrapper = _wrapper.createControlsWrapper(switchElement); formSection.appendChild(switchControlWrapper); //formSection.appendChild(switchElement); /////////////// add this type ////////////// Element firstCaseElement = (Element) case_types.get(controlType.getName()); switchElement.appendChild(firstCaseElement); addComplexType(xForm, modelSection, firstCaseElement, (XSComplexTypeDefinition) controlType, elementDecl, pathToRoot, true, false); /////////////// add sub types ////////////// it = compatibleTypes.iterator(); // add each compatible type within // a case statement while (it.hasNext()) { /*String compatibleTypeName = (String) it.next(); //WARNING: order of parameters inversed from the doc for 2.6.0 !!! XSTypeDefinition type =getSchema().getTypeDefinition( compatibleTypeName, targetNamespace);*/ XSTypeDefinition type = (XSTypeDefinition) it.next(); String compatibleTypeName = type.getName(); if (LOGGER.isDebugEnabled()) { if (type == null) LOGGER.debug(">>>addElement: compatible type is null!! type=" + compatibleTypeName + ", targetNamespace=" + targetNamespace); else LOGGER.debug(" >>>addElement: adding compatible type " + type.getName()); } if (type != null && type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { //Element caseElement = (Element) xForm.createElementNS(XFORMS_NS,getXFormsNSPrefix() + "case"); //caseElement.setAttributeNS(XFORMS_NS,getXFormsNSPrefix() + "id",bindId + "_" + type.getName() +"_case"); //String case_id=this.setXFormsId(caseElement); Element caseElement = (Element) case_types.get(type.getName()); switchElement.appendChild(caseElement); addComplexType(xForm, modelSection, caseElement, (XSComplexTypeDefinition) type, elementDecl, pathToRoot, true, true); ////// // modify bind to add a "relevant" attribute that checks the value of @xsi:type // if (LOGGER.isDebugEnabled()) DOMUtil.prettyPrintDOM(bindElement2); NodeList binds = bindElement2.getElementsByTagNameNS(XFORMS_NS, "bind"); Element thisBind = null; int nb_binds = binds.getLength(); int i = 0; while (i < nb_binds && thisBind == null) { Element subBind = (Element) binds.item(i); String name = subBind.getAttributeNS(XFORMS_NS, "nodeset"); if (LOGGER.isDebugEnabled()) LOGGER.debug("Testing sub-bind with nodeset " + name); if (this.isElementDeclaredIn(name, (XSComplexTypeDefinition) type, false) || this.isAttributeDeclaredIn(name, (XSComplexTypeDefinition) type, false)) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Element/Attribute " + name + " declared in type " + type.getName() + ": adding relevant attribute"); //test sub types of this type TreeSet subCompatibleTypes = (TreeSet) typeTree.get(type.getName()); //TreeSet subCompatibleTypes = (TreeSet) typeTree.get(type); String newRelevant = null; if (subCompatibleTypes == null || subCompatibleTypes.isEmpty()) { //just add ../@xsi:type='type' newRelevant = "../@xsi:type='" + type.getName() + "'"; } else { //add ../@xsi:type='type' or ../@xsi:type='otherType' or ... newRelevant = "../@xsi:type='" + type.getName() + "'"; Iterator it_ct = subCompatibleTypes.iterator(); while (it_ct.hasNext()) { //String otherTypeName = (String) it_ct.next(); XSTypeDefinition otherType = (XSTypeDefinition) it_ct.next(); String otherTypeName = otherType.getName(); newRelevant = newRelevant + " or ../@xsi:type='" + otherTypeName + "'"; } } //change relevant attribute String relevant = subBind.getAttributeNS(XFORMS_NS, "relevant"); if (relevant != null && !relevant.equals("")) { newRelevant = "(" + relevant + ") and " + newRelevant; } if (newRelevant != null && !newRelevant.equals("")) subBind.setAttributeNS(XFORMS_NS, getXFormsNSPrefix() + "relevant", newRelevant); } i++; } } } /*if (LOGGER.isDebugEnabled()) { LOGGER.debug( "###addElement for derived type: bind created:"); DOMUtil.prettyPrintDOM(bindElement2); }*/ // we're done // break; } else if (enumValues.size() == 1) { // only one compatible type, set the controlType value // and fall through // //controlType = getSchema().getComplexType((String)enumValues.get(0)); controlType = getSchema().getTypeDefinition((String) enumValues.get(0), targetNamespace); } } else if (LOGGER.isDebugEnabled()) LOGGER.debug("No compatible type found for " + typeName); //name not null but no compatibleType? relative = true; } if (relative) //create the bind in case it is a repeat { if (LOGGER.isDebugEnabled()) LOGGER.debug(">>>Adding empty bind for " + typeName); // create the <xforms:bind> element and add it to the model. Element bindElement = xForm.createElementNS(XFORMS_NS, getXFormsNSPrefix() + "bind"); String bindId = this.setXFormsId(bindElement); bindElement.setAttributeNS(XFORMS_NS, getXFormsNSPrefix() + "nodeset", pathToRoot); modelSection.appendChild(bindElement); } else if (LOGGER.isDebugEnabled()) { LOGGER.debug("addElement: bind is not relative for " + elementDecl.getName()); } //addComplexType(xForm,modelSection, formSection,(ComplexType)controlType,elementDecl,pathToRoot, relative); addComplexType(xForm, modelSection, formSection, (XSComplexTypeDefinition) controlType, elementDecl, pathToRoot, true, false); break; } } default: // TODO: add wildcard support LOGGER.warn("\nWARNING!!! - Unsupported type [" + elementDecl.getType() + "] for node [" + controlType.getName() + "]"); } }
From source file:io.github.msdk.features.ransacaligner.RansacAlignerMethod.java
private Hashtable<FeatureTableRow, FeatureTableRow> getAlignmentMap(FeatureTable featureTable) { // Create a table of mappings for best scores Hashtable<FeatureTableRow, FeatureTableRow> alignmentMapping = new Hashtable<FeatureTableRow, FeatureTableRow>(); // Create a sorted set of scores matching TreeSet<RowVsRowScore> scoreSet = new TreeSet<RowVsRowScore>(); // RANSAC algorithm List<AlignStructMol> list = ransacPeakLists(result, featureTable); PolynomialFunction function = this.getPolynomialFunction(list); List<FeatureTableRow> allRows = featureTable.getRows(); for (FeatureTableRow row : allRows) { // Calculate limits for a row with which the row can be aligned Range<Double> mzRange = mzTolerance.getToleranceRange(row.getMz()); double rt; try {/*w ww . j a v a 2 s. c o m*/ rt = function.value(row.getChromatographyInfo().getRetentionTime()); } catch (NullPointerException e) { rt = row.getChromatographyInfo().getRetentionTime(); } if (Double.isNaN(rt) || rt == -1) { rt = row.getChromatographyInfo().getRetentionTime(); } Range<Double> rtRange = rtToleranceAfterCorrection.getToleranceRange(rt); // Get all rows of the aligned feature table within the m/z and // RT limits List<FeatureTableRow> candidateRows = result.getRowsInsideRange(rtRange, mzRange); for (FeatureTableRow candidateRow : candidateRows) { RowVsRowScore score; if (requireSameCharge) { FeatureTableColumn<Integer> chargeColumn1 = featureTable.getColumn(ColumnName.CHARGE, null); FeatureTableColumn<Integer> chargeColumn2 = result.getColumn(ColumnName.CHARGE, null); Integer charge1 = row.getData(chargeColumn1); Integer charge2 = candidateRow.getData(chargeColumn2); if (!charge1.equals(charge2)) continue; } // Check ion annotation if (requireSameAnnotation) { FeatureTableColumn<List<IonAnnotation>> ionAnnotationColumn1 = featureTable .getColumn(ColumnName.IONANNOTATION, null); FeatureTableColumn<List<IonAnnotation>> ionAnnotationColumn2 = result .getColumn(ColumnName.IONANNOTATION, null); List<IonAnnotation> ionAnnotations1 = row.getData(ionAnnotationColumn1); List<IonAnnotation> ionAnnotations2 = candidateRow.getData(ionAnnotationColumn2); // Check that all ion annotations in first row are in // the candidate row boolean equalIons = false; if (ionAnnotations1 != null && ionAnnotations2 != null) { for (IonAnnotation ionAnnotation : ionAnnotations1) { for (IonAnnotation targetIonAnnotation : ionAnnotations2) { if (targetIonAnnotation.compareTo(ionAnnotation) == 0) equalIons = true; } } } if (!equalIons) continue; } try { double mzLength = mzRange.upperEndpoint() - mzRange.lowerEndpoint(); double rtLength = rtRange.upperEndpoint() - rtRange.lowerEndpoint(); score = new RowVsRowScore(row, candidateRow, mzLength, rtLength, new Float(rt)); scoreSet.add(score); } catch (Exception e) { return null; } } } // Iterate scores by descending order Iterator<RowVsRowScore> scoreIterator = scoreSet.iterator(); while (scoreIterator.hasNext()) { RowVsRowScore score = scoreIterator.next(); // Check if the row is already mapped if (alignmentMapping.containsKey(score.getFeatureTableRow())) { continue; } // Check if the aligned row is already filled if (alignmentMapping.containsValue(score.getAlignedRow())) { continue; } alignmentMapping.put(score.getFeatureTableRow(), score.getAlignedRow()); } return alignmentMapping; }
From source file:org.apache.lens.cube.metadata.CubeMetastoreClient.java
private LatestInfo getNextLatestOfDimtable(Table hiveTable, String timeCol, final int timeColIndex, UpdatePeriod updatePeriod, Map<String, String> nonTimePartSpec) throws HiveException { // getClient().getPartitionsByNames(tbl, partNames) List<Partition> partitions; try {/*from w ww.j a v a 2s . c o m*/ partitions = getClient().getPartitionsByFilter(hiveTable, StorageConstants.getPartFilter(nonTimePartSpec)); filterPartitionsByUpdatePeriod(partitions, updatePeriod); filterPartitionsByNonTimeParts(partitions, nonTimePartSpec, timeCol); } catch (TException e) { throw new HiveException(e); } // tree set contains partitions with timestamp as value for timeCol, in // descending order TreeSet<Partition> allPartTimeVals = new TreeSet<>(new Comparator<Partition>() { @Override public int compare(Partition o1, Partition o2) { Date partDate1 = getPartDate(o1, timeColIndex); Date partDate2 = getPartDate(o2, timeColIndex); if (partDate1 != null && partDate2 == null) { return -1; } else if (partDate1 == null && partDate2 != null) { return 1; } else if (partDate1 == null) { return o2.getTPartition().compareTo(o1.getTPartition()); } else if (!partDate2.equals(partDate1)) { return partDate2.compareTo(partDate1); } else { return o2.getTPartition().compareTo(o1.getTPartition()); } } }); for (Partition part : partitions) { if (!isLatestPartOfDimtable(part)) { Date partDate = getPartDate(part, timeColIndex); if (partDate != null) { allPartTimeVals.add(part); } } } Iterator<Partition> it = allPartTimeVals.iterator(); it.next(); // Skip itself. We have to find next latest. LatestInfo latest = null; if (it.hasNext()) { Partition nextLatest = it.next(); latest = new LatestInfo(); latest.setPart(nextLatest); Map<String, String> latestParams = LensUtil.getHashMap(getLatestPartTimestampKey(timeCol), nextLatest.getValues().get(timeColIndex)); latest.addLatestPartInfo(timeCol, new LatestPartColumnInfo(latestParams)); } return latest; }
From source file:org.opencms.xml.content.CmsDefaultXmlContentHandler.java
/** * @see org.opencms.xml.content.I_CmsXmlContentHandler#resolveMapping(org.opencms.file.CmsObject, org.opencms.xml.content.CmsXmlContent, org.opencms.xml.types.I_CmsXmlContentValue) *//*ww w. j a va 2 s. c o m*/ public void resolveMapping(CmsObject cms, CmsXmlContent content, I_CmsXmlContentValue value) throws CmsException { if (!value.isSimpleType()) { // no mappings for a nested schema are possible // note that the sub-elements of the nested schema ARE mapped by the node visitor, // it's just the nested schema value itself that does not support mapping return; } // get the original VFS file from the content CmsFile file = content.getFile(); if (file == null) { throw new CmsXmlException(Messages.get().container(Messages.ERR_XMLCONTENT_RESOLVE_FILE_NOT_FOUND_0)); } // get the mappings for the element name List<String> mappings = getMappings(value.getPath()); if (mappings == null) { // nothing to do if we have no mappings at all return; } // create OpenCms user context initialized with "/" as site root to read all siblings CmsObject rootCms = OpenCms.initCmsObject(cms); Object logEntry = cms.getRequestContext().getAttribute(CmsLogEntry.ATTR_LOG_ENTRY); if (logEntry != null) { rootCms.getRequestContext().setAttribute(CmsLogEntry.ATTR_LOG_ENTRY, logEntry); } rootCms.getRequestContext().setSiteRoot("/"); // read all siblings of the file List<CmsResource> siblings = rootCms.readSiblings(content.getFile().getRootPath(), CmsResourceFilter.IGNORE_EXPIRATION); Set<CmsResource> urlNameMappingResources = new HashSet<CmsResource>(); boolean mapToUrlName = false; urlNameMappingResources.add(content.getFile()); // since 7.0.2 multiple mappings are possible for (String mapping : mappings) { // for multiple language mappings, we need to ensure // a) all siblings are handled // b) only the "right" locale is mapped to a sibling if (CmsStringUtil.isNotEmpty(mapping)) { for (int i = (siblings.size() - 1); i >= 0; i--) { // get filename String filename = (siblings.get(i)).getRootPath(); Locale locale = OpenCms.getLocaleManager().getDefaultLocale(rootCms, filename); if (mapping.startsWith(MAPTO_URLNAME)) { // should be written regardless of whether there is a sibling with the correct locale mapToUrlName = true; } if (!locale.equals(value.getLocale())) { // only map property if the locale fits continue; } // make sure the file is locked CmsLock lock = rootCms.getLock(filename); if (lock.isUnlocked()) { rootCms.lockResource(filename); } else if (!lock.isDirectlyOwnedInProjectBy(rootCms)) { rootCms.changeLock(filename); } // get the string value of the current node String stringValue = value.getStringValue(rootCms); if (mapping.startsWith(MAPTO_PERMISSION) && (value.getIndex() == 0)) { // map value to a permission // example of a mapping: mapto="permission:GROUP:+r+v|GROUP.ALL_OTHERS:|GROUP.Projectmanagers:+r+v+w+c" // get permission(s) to set String permissionMappings = mapping.substring(MAPTO_PERMISSION.length()); String mainMapping = permissionMappings; Map<String, String> permissionsToSet = new HashMap<String, String>(); // separate permission to set for element value from other permissions to set int sepIndex = permissionMappings.indexOf('|'); if (sepIndex != -1) { mainMapping = permissionMappings.substring(0, sepIndex); permissionMappings = permissionMappings.substring(sepIndex + 1); permissionsToSet = CmsStringUtil.splitAsMap(permissionMappings, "|", ":"); } // determine principal type and permission string to set String principalType = I_CmsPrincipal.PRINCIPAL_GROUP; String permissionString = mainMapping; sepIndex = mainMapping.indexOf(':'); if (sepIndex != -1) { principalType = mainMapping.substring(0, sepIndex); permissionString = mainMapping.substring(sepIndex + 1); } if (permissionString.toLowerCase().indexOf('o') == -1) { permissionString += "+o"; } // remove all existing permissions from the file List<CmsAccessControlEntry> aces = rootCms.getAccessControlEntries(filename, false); for (Iterator<CmsAccessControlEntry> j = aces.iterator(); j.hasNext();) { CmsAccessControlEntry ace = j.next(); if (ace.getPrincipal().equals(CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_ID)) { // remove the entry "All others", which has to be treated in a special way rootCms.rmacc(filename, CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_NAME, CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_ID.toString()); } else { // this is a group or user principal I_CmsPrincipal principal = CmsPrincipal.readPrincipal(rootCms, ace.getPrincipal()); if (principal.isGroup()) { rootCms.rmacc(filename, I_CmsPrincipal.PRINCIPAL_GROUP, principal.getName()); } else if (principal.isUser()) { rootCms.rmacc(filename, I_CmsPrincipal.PRINCIPAL_USER, principal.getName()); } } } // set additional permissions that are defined in mapping for (Iterator<Map.Entry<String, String>> j = permissionsToSet.entrySet().iterator(); j .hasNext();) { Map.Entry<String, String> entry = j.next(); sepIndex = entry.getKey().indexOf('.'); if (sepIndex != -1) { String type = entry.getKey().substring(0, sepIndex); String name = entry.getKey().substring(sepIndex + 1); String permissions = entry.getValue(); if (permissions.toLowerCase().indexOf('o') == -1) { permissions += "+o"; } try { rootCms.chacc(filename, type, name, permissions); } catch (CmsException e) { // setting permission did not work LOG.error(e); } } } // set permission(s) using the element value(s) // the set with all selected principals TreeSet<String> allPrincipals = new TreeSet<String>(); String path = CmsXmlUtils.removeXpathIndex(value.getPath()); List<I_CmsXmlContentValue> values = content.getValues(path, locale); Iterator<I_CmsXmlContentValue> j = values.iterator(); while (j.hasNext()) { I_CmsXmlContentValue val = j.next(); String principalName = val.getStringValue(rootCms); // the prinicipal name can be a principal list List<String> principalNames = CmsStringUtil.splitAsList(principalName, PRINCIPAL_LIST_SEPARATOR); // iterate over the principals Iterator<String> iterPrincipals = principalNames.iterator(); while (iterPrincipals.hasNext()) { // get the next principal String principal = iterPrincipals.next(); allPrincipals.add(principal); } } // iterate over the set with all principals and set the permissions Iterator<String> iterAllPricinipals = allPrincipals.iterator(); while (iterAllPricinipals.hasNext()) { // get the next principal String principal = iterAllPricinipals.next(); rootCms.chacc(filename, principalType, principal, permissionString); } // special case: permissions are written only to one sibling, end loop i = 0; } else if (mapping.startsWith(MAPTO_PROPERTY_LIST) && (value.getIndex() == 0)) { boolean mapToShared; int prefixLength; // check which mapping is used (shared or individual) if (mapping.startsWith(MAPTO_PROPERTY_LIST_SHARED)) { mapToShared = true; prefixLength = MAPTO_PROPERTY_LIST_SHARED.length(); } else if (mapping.startsWith(MAPTO_PROPERTY_LIST_INDIVIDUAL)) { mapToShared = false; prefixLength = MAPTO_PROPERTY_LIST_INDIVIDUAL.length(); } else { mapToShared = false; prefixLength = MAPTO_PROPERTY_LIST.length(); } // this is a property list mapping String property = mapping.substring(prefixLength); String path = CmsXmlUtils.removeXpathIndex(value.getPath()); List<I_CmsXmlContentValue> values = content.getValues(path, locale); Iterator<I_CmsXmlContentValue> j = values.iterator(); StringBuffer result = new StringBuffer(values.size() * 64); while (j.hasNext()) { I_CmsXmlContentValue val = j.next(); result.append(val.getStringValue(rootCms)); if (j.hasNext()) { result.append(CmsProperty.VALUE_LIST_DELIMITER); } } CmsProperty p; if (mapToShared) { // map to shared value p = new CmsProperty(property, null, result.toString()); } else { // map to individual value p = new CmsProperty(property, result.toString(), null); } // write the created list string value in the selected property rootCms.writePropertyObject(filename, p); if (mapToShared) { // special case: shared mappings must be written only to one sibling, end loop i = 0; } } else if (mapping.startsWith(MAPTO_PROPERTY)) { boolean mapToShared; int prefixLength; // check which mapping is used (shared or individual) if (mapping.startsWith(MAPTO_PROPERTY_SHARED)) { mapToShared = true; prefixLength = MAPTO_PROPERTY_SHARED.length(); } else if (mapping.startsWith(MAPTO_PROPERTY_INDIVIDUAL)) { mapToShared = false; prefixLength = MAPTO_PROPERTY_INDIVIDUAL.length(); } else { mapToShared = false; prefixLength = MAPTO_PROPERTY.length(); } // this is a property mapping String property = mapping.substring(prefixLength); CmsProperty p; if (mapToShared) { // map to shared value p = new CmsProperty(property, null, stringValue); } else { // map to individual value p = new CmsProperty(property, stringValue, null); } // just store the string value in the selected property rootCms.writePropertyObject(filename, p); if (mapToShared) { // special case: shared mappings must be written only to one sibling, end loop i = 0; } } else if (mapping.startsWith(MAPTO_URLNAME)) { // we write the actual mappings later urlNameMappingResources.add(siblings.get(i)); } else if (mapping.startsWith(MAPTO_ATTRIBUTE)) { // this is an attribute mapping String attribute = mapping.substring(MAPTO_ATTRIBUTE.length()); switch (ATTRIBUTES.indexOf(attribute)) { case 0: // date released long date = 0; try { date = Long.valueOf(stringValue).longValue(); } catch (NumberFormatException e) { // ignore, value can be a macro } if (date == 0) { date = CmsResource.DATE_RELEASED_DEFAULT; } // set the sibling release date rootCms.setDateReleased(filename, date, false); // set current file release date if (filename.equals(rootCms.getSitePath(file))) { file.setDateReleased(date); } break; case 1: // date expired date = 0; try { date = Long.valueOf(stringValue).longValue(); } catch (NumberFormatException e) { // ignore, value can be a macro } if (date == 0) { date = CmsResource.DATE_EXPIRED_DEFAULT; } // set the sibling expired date rootCms.setDateExpired(filename, date, false); // set current file expired date if (filename.equals(rootCms.getSitePath(file))) { file.setDateExpired(date); } break; default: // ignore invalid / other mappings } } } } } if (mapToUrlName) { // now actually write the URL name mappings for (CmsResource resourceForUrlNameMapping : urlNameMappingResources) { if (!CmsResource.isTemporaryFileName(resourceForUrlNameMapping.getRootPath())) { I_CmsFileNameGenerator nameGen = OpenCms.getResourceManager().getNameGenerator(); Iterator<String> nameSeq = nameGen.getUrlNameSequence(value.getStringValue(cms)); cms.writeUrlNameMapping(nameSeq, resourceForUrlNameMapping.getStructureId(), value.getLocale().toString()); } } } // make sure the original is locked CmsLock lock = rootCms.getLock(file); if (lock.isUnlocked()) { rootCms.lockResource(file.getRootPath()); } else if (!lock.isExclusiveOwnedBy(rootCms.getRequestContext().getCurrentUser())) { rootCms.changeLock(file.getRootPath()); } }
From source file:org.commonvox.hbase_column_manager.TestRepositoryAdmin.java
private void compareResourceFileToExportedFile(String resourceFileString, File exportedFile, String methodName) throws IOException, URISyntaxException { Path resourcePath = Paths.get(ClassLoader.getSystemResource(resourceFileString).toURI()); assertEquals(CHANGE_EVENT_FAILURE + "unexpected item count from " + methodName + " method", Files.lines(resourcePath).count(), Files.lines(exportedFile.toPath()).count()); // NOTE: timestamps on sequential events can sometimes be equal (if processing is TOO quick!) // so reliable comparison requires stripping initial timestamp from each line and reordering // remainder via TreeSets, then doing comparison. TreeSet<String> resourceLinesTruncated = new TreeSet<>(); TreeSet<String> exportedLinesTruncated = new TreeSet<>(); Iterator<String> resourceLinesIterator = Files.lines(resourcePath).iterator(); Iterator<String> exportedLinesIterator = Files.lines(exportedFile.toPath()).iterator(); int skipCount = 0; while (resourceLinesIterator.hasNext()) { if (skipCount++ < 3) { resourceLinesIterator.next(); // skip comment and header lines in both files exportedLinesIterator.next(); // skip comment and header lines in both files continue; }/*from ww w.ja v a 2s . c om*/ resourceLinesTruncated.add(resourceLinesIterator.next().substring(14)); // strip timestamp exportedLinesTruncated.add(exportedLinesIterator.next().substring(14)); // strip timestamp } Iterator<String> resourceLinesTruncatedIterator = resourceLinesTruncated.iterator(); Iterator<String> exportedLinesTruncatedIterator = exportedLinesTruncated.iterator(); while (resourceLinesTruncatedIterator.hasNext()) { assertEquals(CHANGE_EVENT_FAILURE + "unexpected content returned by " + methodName, resourceLinesTruncatedIterator.next(), exportedLinesTruncatedIterator.next()); } }
From source file:net.sourceforge.fenixedu.domain.student.Registration.java
public PrecedentDegreeInformation getLatestPrecedentDegreeInformation() { TreeSet<PrecedentDegreeInformation> degreeInformations = new TreeSet<PrecedentDegreeInformation>( Collections.reverseOrder(PrecedentDegreeInformation.COMPARATOR_BY_EXECUTION_YEAR)); ExecutionYear currentExecutionYear = ExecutionYear.readCurrentExecutionYear(); for (PrecedentDegreeInformation pdi : getPrecedentDegreesInformationsSet()) { if (!pdi.getExecutionYear().isAfter(currentExecutionYear)) { degreeInformations.add(pdi); }//from w ww . j a v a 2 s . co m } if (degreeInformations.isEmpty()) { return null; } return degreeInformations.iterator().next(); }
From source file:org.dasein.cloud.vcloud.vCloudMethod.java
private @Nonnull Version getVersion() throws CloudException, InternalException { Cache<Version> cache = Cache.getInstance(provider, "vCloudVersions", Version.class, CacheLevel.CLOUD, new TimePeriod<Day>(1, TimePeriod.DAY)); ProviderContext ctx = provider.getContext(); if (ctx == null) { throw new CloudException("No context was defined for this request"); }/*w ww . j a v a 2s.c om*/ { Iterable<Version> versions = cache.get(ctx); Iterator<Version> it = (versions == null ? null : versions.iterator()); if (it != null && it.hasNext()) { return it.next(); } } // TODO: how does vCHS do version discovery? if (ctx.getCloud().getEndpoint().startsWith("https://vchs")) { // This is a complete hack that needs to be changed to reflect vCHS version discovery Version version = new Version(); version.loginUrl = ctx.getCloud().getEndpoint() + "/api/vchs/sessions"; version.version = "5.6"; cache.put(ctx, Collections.singletonList(version)); return version; } if (wire.isDebugEnabled()) { wire.debug(""); wire.debug(">>> [GET (" + (new Date()) + ")] -> " + ctx.getCloud().getEndpoint() + " >--------------------------------------------------------------------------------------"); } try { final String[] preferred = provider.getVersionPreference(); HttpClient client = getClient(false); HttpGet method = new HttpGet(ctx.getCloud().getEndpoint() + "/api/versions"); if (wire.isDebugEnabled()) { wire.debug(method.getRequestLine().toString()); for (Header header : method.getAllHeaders()) { wire.debug(header.getName() + ": " + header.getValue()); } wire.debug(""); } HttpResponse response; StatusLine status; try { APITrace.trace(provider, "GET versions"); response = client.execute(method); if (wire.isDebugEnabled()) { wire.debug(response.getStatusLine().toString()); for (Header header : response.getAllHeaders()) { wire.debug(header.getName() + ": " + header.getValue()); } wire.debug(""); } status = response.getStatusLine(); } catch (IOException e) { throw new CloudException(e); } if (status.getStatusCode() == HttpServletResponse.SC_OK) { HttpEntity entity = response.getEntity(); String body; try { body = EntityUtils.toString(entity); if (wire.isDebugEnabled()) { wire.debug(body); wire.debug(""); } } catch (IOException e) { throw new CloudException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), e.getMessage()); } try { ByteArrayInputStream bas = new ByteArrayInputStream(body.getBytes()); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = factory.newDocumentBuilder(); Document doc = parser.parse(bas); bas.close(); NodeList versions = doc.getElementsByTagName("VersionInfo"); TreeSet<Version> set = new TreeSet<Version>(new Comparator<Version>() { public int compare(Version version1, Version version2) { if (version1.equals(version2)) { return 0; } if (preferred != null) { for (String v : preferred) { if (v.equals(version1.version)) { return -1; } else if (v.equals(version2.version)) { return 1; } } } for (String v : VERSIONS) { if (v.equals(version1.version)) { return -1; } else if (v.equals(version2.version)) { return 1; } } return -version1.version.compareTo(version2.version); } }); for (int i = 0; i < versions.getLength(); i++) { Node versionInfo = versions.item(i); NodeList vattrs = versionInfo.getChildNodes(); String version = null; String url = null; for (int j = 0; j < vattrs.getLength(); j++) { Node attr = vattrs.item(j); if (attr.getNodeName().equalsIgnoreCase("Version") && attr.hasChildNodes()) { version = attr.getFirstChild().getNodeValue().trim(); } else if (attr.getNodeName().equalsIgnoreCase("LoginUrl") && attr.hasChildNodes()) { url = attr.getFirstChild().getNodeValue().trim(); } } if (version == null || url == null || !isSupported(version)) { continue; } Version v = new Version(); v.version = version; v.loginUrl = url; set.add(v); } if (set.isEmpty()) { throw new CloudException("Unable to identify a supported version"); } Version v = set.iterator().next(); cache.put(ctx, set); return v; } catch (IOException e) { throw new CloudException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), e.getMessage()); } catch (ParserConfigurationException e) { throw new CloudException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), e.getMessage()); } catch (SAXException e) { throw new CloudException(CloudErrorType.GENERAL, status.getStatusCode(), status.getReasonPhrase(), e.getMessage()); } } else { logger.error("Expected OK for GET request, got " + status.getStatusCode()); String xml = null; try { HttpEntity entity = response.getEntity(); if (entity != null) { xml = EntityUtils.toString(entity); if (wire.isDebugEnabled()) { wire.debug(xml); wire.debug(""); } } } catch (IOException e) { logger.error("Failed to read response error due to a cloud I/O error: " + e.getMessage()); throw new CloudException(e); } vCloudException.Data data = null; if (xml != null && !xml.equals("")) { Document doc = parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList errors = doc.getElementsByTagName(nsString + "Error"); if (errors.getLength() > 0) { data = vCloudException.parseException(status.getStatusCode(), errors.item(0)); } } if (data == null) { throw new vCloudException(CloudErrorType.GENERAL, status.getStatusCode(), response.getStatusLine().getReasonPhrase(), "No further information"); } logger.error("[" + status.getStatusCode() + " : " + data.title + "] " + data.description); throw new vCloudException(data); } } finally { if (wire.isDebugEnabled()) { wire.debug("<<< [GET (" + (new Date()) + ")] -> " + ctx.getEndpoint() + " <--------------------------------------------------------------------------------------"); wire.debug(""); } } }
From source file:org.zaproxy.zap.extension.ascanrulesBeta.SessionFixation.java
/** * scans all GET, Cookie params for Session fields, and looks for SessionFixation * vulnerabilities/*w w w. j a v a2 s . c om*/ */ @Override public void scan() { // TODO: scan the POST (form) params for session id fields. try { boolean loginUrl = false; // Are we dealing with a login url in any of the contexts of which this uri is part URI requestUri = getBaseMsg().getRequestHeader().getURI(); ExtensionAuthentication extAuth = (ExtensionAuthentication) Control.getSingleton().getExtensionLoader() .getExtension(ExtensionAuthentication.NAME); // using the session, get the list of contexts for the url List<Context> contextList = extAuth.getModel().getSession().getContextsForUrl(requestUri.getURI()); // now loop, and see if the url is a login url in each of the contexts in turn... for (Context context : contextList) { URI loginUri = extAuth.getLoginRequestURIForContext(context); if (loginUri != null && requestUri.getPath() != null) { if (requestUri.getScheme().equals(loginUri.getScheme()) && requestUri.getHost().equals(loginUri.getHost()) && requestUri.getPort() == loginUri.getPort() && requestUri.getPath().equals(loginUri.getPath())) { // we got this far.. only the method (GET/POST), user details, query params, // fragment, and POST params // are possibly different from the login page. loginUrl = true; break; } } } // For now (from Zap 2.0), the Session Fixation scanner will only run for login pages if (loginUrl == false) { log.debug("For the Session Fixation scanner to actually do anything, a Login Page *must* be set!"); return; } // find all params set in the request (GET/POST/Cookie) // Note: this will be the full set, before we delete anything. TreeSet<HtmlParameter> htmlParams = new TreeSet<>(); htmlParams.addAll(getBaseMsg().getRequestHeader().getCookieParams()); // request cookies only. no response cookies htmlParams.addAll(getBaseMsg().getFormParams()); // add in the POST params htmlParams.addAll(getBaseMsg().getUrlParams()); // add in the GET params // Now add in the pseudo parameters set in the URL itself, such as in the following: // http://www.example.com/someurl;JSESSIONID=abcdefg?x=123&y=456 // as opposed to the url parameters in the following example, which are already picked // up by getUrlParams() // http://www.example.com/someurl?JSESSIONID=abcdefg&x=123&y=456 // convert from org.apache.commons.httpclient.URI to a String String requestUrl = "Unknown URL"; try { requestUrl = new URL(requestUri.getScheme(), requestUri.getHost(), requestUri.getPort(), requestUri.getPath()).toString(); } catch (Exception e) { // no point in continuing. The URL is invalid. This is a peculiarity in the Zap // core, // and can happen when // - the user browsed to http://www.example.com/bodgeit and // - the user did not browse to http://www.example.com or to http://www.example.com/ // so the Zap GUI displays "http://www.example.com" as a node under "Sites", // and under that, it displays the actual urls to which the user browsed // (http://www.example.com/bodgeit, for instance) // When the user selects the node "http://www.example.com", and tries to scan it // with // the session fixation scanner, the URI that is passed is "http://www.example.com", // which is *not* a valid url. // If the user actually browses to "http://www.example.com" (even without the // trailing slash) // the web browser appends the trailing slash, and so Zap records the URI as // "http://www.example.com/", which IS a valid url, and which can (and should) be // scanned. // // In short.. if this happens, we do not want to scan the URL anyway // (because the user never browsed to it), so just do nothing instead. log.error("Cannot convert URI [" + requestUri + "] to a URL: " + e.getMessage()); return; } // suck out any pseudo url parameters from the url Set<HtmlParameter> pseudoUrlParams = getPseudoUrlParameters(requestUrl); htmlParams.addAll(pseudoUrlParams); if (this.debugEnabled) log.debug("Pseudo url params of URL [" + requestUrl + "] : [" + pseudoUrlParams + "]"); //// for each parameter in turn, // int counter = 0; for (Iterator<HtmlParameter> iter = htmlParams.iterator(); iter.hasNext();) { HttpMessage msg1Final; HttpMessage msg1Initial = getNewMsg(); //// debug logic only.. to do first field only // counter ++; // if ( counter > 1 ) // return; HtmlParameter currentHtmlParameter = iter.next(); // Useful for debugging, but I can't find a way to view this data in the GUI, so // leave it out for now. // msg1Initial.setNote("Message 1 for parameter "+ currentHtmlParameter); if (this.debugEnabled) log.debug("Scanning URL [" + msg1Initial.getRequestHeader().getMethod() + "] [" + msg1Initial.getRequestHeader().getURI() + "], [" + currentHtmlParameter.getType() + "] field [" + currentHtmlParameter.getName() + "] with value [" + currentHtmlParameter.getValue() + "] for Session Fixation"); if (currentHtmlParameter.getType().equals(HtmlParameter.Type.cookie)) { // careful to pick up the cookies from the Request, and not to include cookies // set in any earlier response TreeSet<HtmlParameter> cookieRequestParams = msg1Initial.getRequestHeader().getCookieParams(); // delete the original cookie from the parameters cookieRequestParams.remove(currentHtmlParameter); msg1Initial.setCookieParams(cookieRequestParams); // send the message, minus the cookie parameter, and see how it comes back. // Note: do NOT automatically follow redirects.. handle those here instead. sendAndReceive(msg1Initial, false, false); ///////////////////////////// // create a copy of msg1Initial to play with to handle redirects (if any). // we use a copy because if we change msg1Initial itself, it messes the URL and // params displayed on the GUI. msg1Final = msg1Initial; HtmlParameter cookieBack1 = getResponseCookie(msg1Initial, currentHtmlParameter.getName()); long cookieBack1TimeReceived = System.currentTimeMillis(); // in ms. when was the cookie received? // Important if it has a Max-Age directive Date cookieBack1ExpiryDate = null; HttpMessage temp = msg1Initial; int redirectsFollowed1 = 0; while (HttpStatusCode.isRedirection(temp.getResponseHeader().getStatusCode())) { // Note that we need to clone the Request and the Response.. // we seem to need to track the secure flag now to make sure its set later boolean secure1 = temp.getRequestHeader().isSecure(); temp = temp.cloneAll(); // clone the previous message redirectsFollowed1++; if (redirectsFollowed1 > 10) { throw new Exception("Too many redirects were specified in the first message"); } // create a new URI from the absolute location returned, and interpret it as // escaped // note that the standard says that the Location returned should be // absolute, but it ain't always so... URI newLocation = new URI(temp.getResponseHeader().getHeader(HttpHeader.LOCATION), true); // and follow the forward url // need to clear the params (which would come from the initial POST, // otherwise) temp.getRequestHeader().setGetParams(new TreeSet<HtmlParameter>()); temp.setRequestBody(""); temp.setResponseBody(""); // make sure no values accidentally carry from one iteration to // the next try { temp.getRequestHeader().setURI(newLocation); } catch (Exception e) { // the Location field contents may not be standards compliant. Lets // generate a uri to use as a workaround where a relative path was // given instead of an absolute one URI newLocationWorkaround = new URI(temp.getRequestHeader().getURI(), temp.getResponseHeader().getHeader(HttpHeader.LOCATION), true); // try again, except this time, if it fails, don't try to handle it if (this.debugEnabled) log.debug("The Location [" + newLocation + "] specified in a redirect was not valid. Trying workaround url [" + newLocationWorkaround + "]"); temp.getRequestHeader().setURI(newLocationWorkaround); } temp.getRequestHeader().setSecure(secure1); temp.getRequestHeader().setMethod(HttpRequestHeader.GET); temp.getRequestHeader().setContentLength(0); // since we send a GET, the body will be 0 long if (cookieBack1 != null) { // if the previous request sent back a cookie, we need to set that // cookie when following redirects, as a browser would if (this.debugEnabled) log.debug("Adding in cookie [" + cookieBack1 + "] for a redirect"); TreeSet<HtmlParameter> forwardCookieParams = temp.getRequestHeader().getCookieParams(); forwardCookieParams.add(cookieBack1); temp.getRequestHeader().setCookieParams(forwardCookieParams); } if (this.debugEnabled) log.debug("DEBUG: Cookie Message 1 causes us to follow redirect to [" + newLocation + "]"); sendAndReceive(temp, false, false); // do NOT redirect.. handle it here // handle any cookies set from following redirects that override the cookie // set in the redirect itself (if any) // note that this will handle the case where a latter cookie unsets one set // earlier. HtmlParameter cookieBack1Temp = getResponseCookie(temp, currentHtmlParameter.getName()); if (cookieBack1Temp != null) { cookieBack1 = cookieBack1Temp; cookieBack1TimeReceived = System.currentTimeMillis(); // in ms. record when we got the // cookie.. in case it has a // Max-Age directive } // reset the "final" version of message1 to use the final response in the // chain msg1Final = temp; } /////////////////////////// // if non-200 on the final response for message 1, no point in continuing. Bale // out. if (msg1Final.getResponseHeader().getStatusCode() != HttpStatusCode.OK) { if (this.debugEnabled) log.debug( "Got a non-200 response code [" + msg1Final.getResponseHeader().getStatusCode() + "] when sending [" + msg1Initial.getRequestHeader().getURI() + "] with param [" + currentHtmlParameter.getName() + "] = NULL (possibly somewhere in the redirects)"); continue; } // now check that the response set a cookie. if it didn't, then either.. // 1) we are messing with the wrong field // 2) the app doesn't do sessions // either way, there is not much point in continuing to look at this field.. if (cookieBack1 == null || cookieBack1.getValue() == null) { // no cookie was set, or the cookie param was set to a null value if (this.debugEnabled) log.debug("The Cookie parameter was NOT set in the response, when cookie param [" + currentHtmlParameter.getName() + "] was set to NULL: " + cookieBack1); continue; } ////////////////////////////////////////////////////////////////////// // at this point, before continuing to check for Session Fixation, do some other // checks on the session cookie we got back // that might cause us to raise additional alerts (in addition to doing the main // check for Session Fixation) ////////////////////////////////////////////////////////////////////// // Check 1: was the session cookie sent and received securely by the server? // If not, alert this fact if ((!msg1Final.getRequestHeader().isSecure()) || (!cookieBack1.getFlags().contains("secure"))) { // pass the original param value here, not the new value, since we're // displaying the session id exposed in the original message String extraInfo = Constant.messages.getString( "ascanbeta.sessionidsentinsecurely.alert.extrainfo", currentHtmlParameter.getType(), currentHtmlParameter.getName(), currentHtmlParameter.getValue()); if (!cookieBack1.getFlags().contains("secure")) { extraInfo += ("\n" + Constant.messages.getString( "ascanbeta.sessionidsentinsecurely.alert.extrainfo.secureflagnotset")); } // and figure out the risk, depending on whether it is a login page int risk = Alert.RISK_LOW; if (loginUrl) { extraInfo += ("\n" + Constant.messages .getString("ascanbeta.sessionidsentinsecurely.alert.extrainfo.loginpage")); // login page, so higher risk risk = Alert.RISK_MEDIUM; } else { // not a login page.. lower risk risk = Alert.RISK_LOW; } String attack = Constant.messages.getString( "ascanbeta.sessionidsentinsecurely.alert.attack", currentHtmlParameter.getType(), currentHtmlParameter.getName()); String vulnname = Constant.messages.getString("ascanbeta.sessionidsentinsecurely.name"); String vulndesc = Constant.messages.getString("ascanbeta.sessionidsentinsecurely.desc"); String vulnsoln = Constant.messages.getString("ascanbeta.sessionidsentinsecurely.soln"); // call bingo with some extra info, indicating that the alert is // not specific to Session Fixation, but has its own title and description // (etc) // the alert here is "Session id sent insecurely", or words to that effect. bingo(risk, Alert.CONFIDENCE_MEDIUM, vulnname, vulndesc, getBaseMsg().getRequestHeader().getURI().getURI(), currentHtmlParameter.getName(), attack, extraInfo, vulnsoln, getBaseMsg()); if (log.isDebugEnabled()) { String logMessage = MessageFormat.format( "A session identifier in {2} field: [{3}] may be sent " + "via an insecure mechanism at [{0}] URL [{1}]", getBaseMsg().getRequestHeader().getMethod(), getBaseMsg().getRequestHeader().getURI().getURI(), currentHtmlParameter.getType(), currentHtmlParameter.getName()); log.debug(logMessage); } // Note: do NOT continue to the next field at this point.. // since we still need to check for Session Fixation. } ////////////////////////////////////////////////////////////////////// // Check 2: is the session cookie that was set accessible to Javascript? // If so, alert this fact too if (!cookieBack1.getFlags().contains("httponly") && loginUrl) { // pass the original param value here, not the new value, since we're // displaying the session id exposed in the original message String extraInfo = Constant.messages.getString( "ascanbeta.sessionidaccessiblebyjavascript.alert.extrainfo", currentHtmlParameter.getType(), currentHtmlParameter.getName(), currentHtmlParameter.getValue()); String attack = Constant.messages.getString( "ascanbeta.sessionidaccessiblebyjavascript.alert.attack", currentHtmlParameter.getType(), currentHtmlParameter.getName()); String vulnname = Constant.messages .getString("ascanbeta.sessionidaccessiblebyjavascript.name"); String vulndesc = Constant.messages .getString("ascanbeta.sessionidaccessiblebyjavascript.desc"); String vulnsoln = Constant.messages .getString("ascanbeta.sessionidaccessiblebyjavascript.soln"); extraInfo += ("\n" + Constant.messages .getString("ascanbeta.sessionidaccessiblebyjavascript.alert.extrainfo.loginpage")); // call bingo with some extra info, indicating that the alert is // not specific to Session Fixation, but has its own title and description // (etc) // the alert here is "Session id accessible in Javascript", or words to that // effect. bingo(Alert.RISK_LOW, Alert.CONFIDENCE_MEDIUM, vulnname, vulndesc, getBaseMsg().getRequestHeader().getURI().getURI(), currentHtmlParameter.getName(), attack, extraInfo, vulnsoln, getBaseMsg()); if (log.isDebugEnabled()) { String logMessage = MessageFormat.format( "A session identifier in [{0}] URL [{1}] {2} field: " + "[{3}] may be accessible to JavaScript", getBaseMsg().getRequestHeader().getMethod(), getBaseMsg().getRequestHeader().getURI().getURI(), currentHtmlParameter.getType(), currentHtmlParameter.getName()); log.debug(logMessage); } // Note: do NOT continue to the next field at this point.. // since we still need to check for Session Fixation. } ////////////////////////////////////////////////////////////////////// // Check 3: is the session cookie set to expire soon? when the browser session // closes? never? // the longer the session cookie is valid, the greater the risk. alert it // accordingly String cookieBack1Expiry = null; int sessionExpiryRiskLevel; String sessionExpiryDescription = null; // check for the Expires header for (Iterator<String> i = cookieBack1.getFlags().iterator(); i.hasNext();) { String cookieBack1Flag = i.next(); // if ( this.debugEnabled ) log.debug("Cookie back 1 flag (checking for // Expires): "+ cookieBack1Flag); // match in a case insensitive manner. never know what case various web // servers are going to send back. // if (cookieBack1Flag.matches("(?i)expires=.*")) { if (cookieBack1Flag.toLowerCase(Locale.ENGLISH).startsWith("expires=")) { String[] cookieBack1FlagValues = cookieBack1Flag.split("="); if (cookieBack1FlagValues.length > 1) { if (this.debugEnabled) log.debug("Cookie Expiry: " + cookieBack1FlagValues[1]); cookieBack1Expiry = cookieBack1FlagValues[1]; // the Date String sessionExpiryDescription = cookieBack1FlagValues[1]; // the Date String cookieBack1ExpiryDate = DateUtil.parseDate(cookieBack1Expiry); // the actual Date } } } // also check for the Max-Age header, which overrides the Expires header. // WARNING: this Directive is reported to be ignored by IE, so if both Expires // and Max-Age are present // and we report based on the Max-Age value, but the user is using IE, then the // results reported // by us here may be different from those actually experienced by the user! (we // use Max-Age, IE uses Expires) for (Iterator<String> i = cookieBack1.getFlags().iterator(); i.hasNext();) { String cookieBack1Flag = i.next(); // if ( this.debugEnabled ) log.debug("Cookie back 1 flag (checking for // Max-Age): "+ cookieBack1Flag); // match in a case insensitive manner. never know what case various web // servers are going to send back. if (cookieBack1Flag.toLowerCase(Locale.ENGLISH).startsWith("max-age=")) { String[] cookieBack1FlagValues = cookieBack1Flag.split("="); if (cookieBack1FlagValues.length > 1) { // now the Max-Age value is the number of seconds relative to the // time the browser received the cookie // (as stored in cookieBack1TimeReceived) if (this.debugEnabled) log.debug("Cookie Max Age: " + cookieBack1FlagValues[1]); long cookie1DropDeadMS = cookieBack1TimeReceived + (Long.parseLong(cookieBack1FlagValues[1]) * 1000); cookieBack1ExpiryDate = new Date(cookie1DropDeadMS); // the actual Date the cookie // expires (by Max-Age) cookieBack1Expiry = DateUtil.formatDate(cookieBack1ExpiryDate, DateUtil.PATTERN_RFC1123); sessionExpiryDescription = cookieBack1Expiry; // needs to the Date String } } } String sessionExpiryRiskDescription = null; // check the Expiry/Max-Age details garnered (if any) // and figure out the risk, depending on whether it is a login page // and how long the session will live before expiring if (cookieBack1ExpiryDate == null) { // session expires when the browser closes.. rate this as medium risk? sessionExpiryRiskLevel = Alert.RISK_MEDIUM; sessionExpiryRiskDescription = "ascanbeta.sessionidexpiry.browserclose"; sessionExpiryDescription = Constant.messages.getString(sessionExpiryRiskDescription); } else { long datediffSeconds = (cookieBack1ExpiryDate.getTime() - cookieBack1TimeReceived) / 1000; long anHourSeconds = 3600; long aDaySeconds = anHourSeconds * 24; long aWeekSeconds = aDaySeconds * 7; if (datediffSeconds < 0) { if (this.debugEnabled) log.debug("The session cookie has expired already"); sessionExpiryRiskDescription = "ascanbeta.sessionidexpiry.timeexpired"; sessionExpiryRiskLevel = Alert.RISK_INFO; // no risk.. the cookie has expired already } else if (datediffSeconds > aWeekSeconds) { if (this.debugEnabled) log.debug("The session cookie is set to last for more than a week!"); sessionExpiryRiskDescription = "ascanbeta.sessionidexpiry.timemorethanoneweek"; sessionExpiryRiskLevel = Alert.RISK_HIGH; } else if (datediffSeconds > aDaySeconds) { if (this.debugEnabled) log.debug("The session cookie is set to last for more than a day"); sessionExpiryRiskDescription = "ascanbeta.sessionidexpiry.timemorethanoneday"; sessionExpiryRiskLevel = Alert.RISK_MEDIUM; } else if (datediffSeconds > anHourSeconds) { if (this.debugEnabled) log.debug("The session cookie is set to last for more than an hour"); sessionExpiryRiskDescription = "ascanbeta.sessionidexpiry.timemorethanonehour"; sessionExpiryRiskLevel = Alert.RISK_LOW; } else { if (this.debugEnabled) log.debug("The session cookie is set to last for less than an hour!"); sessionExpiryRiskDescription = "ascanbeta.sessionidexpiry.timelessthanonehour"; sessionExpiryRiskLevel = Alert.RISK_INFO; } } if (!loginUrl) { // decrement the risk if it's not a login page sessionExpiryRiskLevel--; } // alert it if the default session expiry risk level is more than informational if (sessionExpiryRiskLevel > Alert.RISK_INFO) { // pass the original param value here, not the new value String cookieReceivedTime = cookieBack1Expiry = DateUtil .formatDate(new Date(cookieBack1TimeReceived), DateUtil.PATTERN_RFC1123); String extraInfo = Constant.messages.getString("ascanbeta.sessionidexpiry.alert.extrainfo", currentHtmlParameter.getType(), currentHtmlParameter.getName(), currentHtmlParameter.getValue(), sessionExpiryDescription, cookieReceivedTime); String attack = Constant.messages.getString("ascanbeta.sessionidexpiry.alert.attack", currentHtmlParameter.getType(), currentHtmlParameter.getName()); String vulnname = Constant.messages.getString("ascanbeta.sessionidexpiry.name"); String vulndesc = Constant.messages.getString("ascanbeta.sessionidexpiry.desc"); String vulnsoln = Constant.messages.getString("ascanbeta.sessionidexpiry.soln"); if (loginUrl) { extraInfo += ("\n" + Constant.messages .getString("ascanbeta.sessionidexpiry.alert.extrainfo.loginpage")); } // call bingo with some extra info, indicating that the alert is // not specific to Session Fixation, but has its own title and description // (etc) // the alert here is "Session Id Expiry Time is excessive", or words to that // effect. bingo(sessionExpiryRiskLevel, Alert.CONFIDENCE_MEDIUM, vulnname, vulndesc, getBaseMsg().getRequestHeader().getURI().getURI(), currentHtmlParameter.getName(), attack, extraInfo, vulnsoln, getBaseMsg()); if (log.isDebugEnabled()) { String logMessage = MessageFormat.format( "A session identifier in [{0}] URL [{1}] {2} field: " + "[{3}] may be accessed until [{4}], unless the session is destroyed.", getBaseMsg().getRequestHeader().getMethod(), getBaseMsg().getRequestHeader().getURI().getURI(), currentHtmlParameter.getType(), currentHtmlParameter.getName(), sessionExpiryDescription); log.debug(logMessage); } // Note: do NOT continue to the next field at this point.. // since we still need to check for Session Fixation. } if (!loginUrl) { // not a login page.. skip continue; } //////////////////////////////////////////////////////////////////////////////////////////// /// Message 2 - processing starts here //////////////////////////////////////////////////////////////////////////////////////////// // so now that we know the URL responds with 200 (OK), and that it sets a // cookie, lets re-issue the original request, // but lets add in the new (valid) session cookie that was just issued. // we will re-send it. the aim is then to see if it accepts the cookie (BAD, in // some circumstances), // or if it issues a new session cookie (GOOD, in most circumstances) if (this.debugEnabled) log.debug("A Cookie was set by the URL for the correct param, when param [" + currentHtmlParameter.getName() + "] was set to NULL: " + cookieBack1); // use a copy of msg2Initial, since it has already had the correct cookie // removed in the request.. // do NOT use msg2Initial itself, as this will cause both requests in the GUI to // show the modified data.. // finally send the second message, and see how it comes back. HttpMessage msg2Initial = msg1Initial.cloneRequest(); TreeSet<HtmlParameter> cookieParams2Set = msg2Initial.getRequestHeader().getCookieParams(); cookieParams2Set.add(cookieBack1); msg2Initial.setCookieParams(cookieParams2Set); // resend the copy of the initial message, but with the valid session cookie // added in, to see if it is accepted // do not automatically follow redirects, as we need to check these for cookies // being set. sendAndReceive(msg2Initial, false, false); // create a copy of msg2Initial to play with to handle redirects (if any). // we use a copy because if we change msg2Initial itself, it messes the URL and // params displayed on the GUI. HttpMessage temp2 = msg2Initial; HttpMessage msg2Final = msg2Initial; HtmlParameter cookieBack2Previous = cookieBack1; HtmlParameter cookieBack2 = getResponseCookie(msg2Initial, currentHtmlParameter.getName()); int redirectsFollowed2 = 0; while (HttpStatusCode.isRedirection(temp2.getResponseHeader().getStatusCode())) { // clone the previous message boolean secure2 = temp2.getRequestHeader().isSecure(); temp2 = temp2.cloneAll(); redirectsFollowed2++; if (redirectsFollowed2 > 10) { throw new Exception("Too many redirects were specified in the second message"); } // create a new URI from the absolute location returned, and interpret it as // escaped // note that the standard says that the Location returned should be // absolute, but it ain't always so... URI newLocation = new URI(temp2.getResponseHeader().getHeader(HttpHeader.LOCATION), true); // and follow the forward url // need to clear the params (which would come from the initial POST, // otherwise) temp2.getRequestHeader().setGetParams(new TreeSet<HtmlParameter>()); temp2.setRequestBody(""); temp2.setResponseBody(""); // make sure no values accidentally carry from one iteration to // the next try { temp2.getRequestHeader().setURI(newLocation); } catch (Exception e) { // the Location field contents may not be standards compliant. Lets // generate a uri to use as a workaround where a relative path was // given instead of an absolute one URI newLocationWorkaround = new URI(temp2.getRequestHeader().getURI(), temp2.getResponseHeader().getHeader(HttpHeader.LOCATION), true); // try again, except this time, if it fails, don't try to handle it if (this.debugEnabled) log.debug("The Location [" + newLocation + "] specified in a redirect was not valid. Trying workaround url [" + newLocationWorkaround + "]"); temp2.getRequestHeader().setURI(newLocationWorkaround); } temp2.getRequestHeader().setSecure(secure2); temp2.getRequestHeader().setMethod(HttpRequestHeader.GET); temp2.getRequestHeader().setContentLength(0); // since we send a GET, the body will be 0 long if (cookieBack2 != null) { // if the previous request sent back a cookie, we need to set that // cookie when following redirects, as a browser would // also make sure to delete the previous value set for the cookie value if (this.debugEnabled) { log.debug("Deleting old cookie [" + cookieBack2Previous + "], and adding in cookie [" + cookieBack2 + "] for a redirect"); } TreeSet<HtmlParameter> forwardCookieParams = temp2.getRequestHeader().getCookieParams(); forwardCookieParams.remove(cookieBack2Previous); forwardCookieParams.add(cookieBack2); temp2.getRequestHeader().setCookieParams(forwardCookieParams); } sendAndReceive(temp2, false, false); // do NOT automatically redirect.. handle redirects here // handle any cookies set from following redirects that override the cookie // set in the redirect itself (if any) // note that this will handle the case where a latter cookie unsets one set // earlier. HtmlParameter cookieBack2Temp = getResponseCookie(temp2, currentHtmlParameter.getName()); if (cookieBack2Temp != null) { cookieBack2Previous = cookieBack2; cookieBack2 = cookieBack2Temp; } // reset the "final" version of message2 to use the final response in the // chain msg2Final = temp2; } if (this.debugEnabled) log.debug("Done following redirects"); // final result was non-200, no point in continuing. Bale out. if (msg2Final.getResponseHeader().getStatusCode() != HttpStatusCode.OK) { if (this.debugEnabled) log.debug( "Got a non-200 response code [" + msg2Final.getResponseHeader().getStatusCode() + "] when sending [" + msg2Initial.getRequestHeader().getURI() + "] with a borrowed cookie (or by following a redirect) for param [" + currentHtmlParameter.getName() + "]"); continue; // to next parameter } // and what we've been waiting for.. do we get a *different* cookie being set in // the response of message 2?? // or do we get a new cookie back at all? // No cookie back => the borrowed cookie was accepted. Not ideal // Cookie back, but same as the one we sent in => the borrowed cookie was // accepted. Not ideal if ((cookieBack2 == null) || cookieBack2.getValue().equals(cookieBack1.getValue())) { // no cookie back, when a borrowed cookie is in use.. suspicious! // use the cookie extrainfo message, which is specific to the case of // cookies // pretty much everything else is generic to all types of Session Fixation // vulnerabilities String extraInfo = Constant.messages.getString( "ascanbeta.sessionfixation.alert.cookie.extrainfo", currentHtmlParameter.getName(), cookieBack1.getValue(), (cookieBack2 == null ? "NULL" : cookieBack2.getValue())); String attack = Constant.messages.getString("ascanbeta.sessionfixation.alert.attack", currentHtmlParameter.getType(), currentHtmlParameter.getName()); if (loginUrl) { extraInfo += ("\n" + Constant.messages .getString("ascanbeta.sessionfixation.alert.cookie.extrainfo.loginpage")); } bingo(Alert.RISK_INFO, Alert.CONFIDENCE_MEDIUM, msg2Initial.getRequestHeader().getURI().getURI(), currentHtmlParameter.getName(), attack, extraInfo, msg2Initial); logSessionFixation(msg2Initial, currentHtmlParameter.getType().toString(), currentHtmlParameter.getName()); } continue; // jump to the next iteration of the loop (ie, the next parameter) } // end of the cookie code. // start of the url parameter code // note that this actually caters for // - actual URL parameters // - pseudo URL parameters, where the sessionid was in the path portion of the URL, // in conjunction with URL re-writing if (currentHtmlParameter.getType().equals(HtmlParameter.Type.url)) { boolean isPseudoUrlParameter = false; // is this "url parameter" actually a url parameter, or was it // path of the path (+url re-writing)? String possibleSessionIdIssuedForUrlParam = null; // remove the named url parameter from the request.. TreeSet<HtmlParameter> urlRequestParams = msg1Initial.getUrlParams(); // get parameters? if (!urlRequestParams.remove(currentHtmlParameter)) { isPseudoUrlParameter = true; // was not removed because it was a pseudo Url parameter, not a real url // parameter.. (so it would not be in the url params) // in this case, we will need to "rewrite" (ie hack) the URL path to remove // the pseudo url parameter portion // ie, we need to remove the ";jsessionid=<sessionid>" bit from the path // (assuming the current field is named 'jsessionid') // and replace it with ";jsessionid=" (ie, we nullify the possible "session" // parameter in the hope that a new session will be issued) // then we continue as usual to see if the URL is vulnerable to a Session // Fixation issue // Side note: quote the string to search for, and the replacement, so that // regex special characters are treated as literals String hackedUrl = requestUrl.replaceAll( Pattern.quote(";" + currentHtmlParameter.getName() + "=" + currentHtmlParameter.getValue()), Matcher.quoteReplacement(";" + currentHtmlParameter.getName() + "=")); if (this.debugEnabled) log.debug("Removing the pseudo URL parameter from [" + requestUrl + "]: [" + hackedUrl + "]"); // Note: the URL is not escaped. Handle it. msg1Initial.getRequestHeader().setURI(new URI(hackedUrl, false)); } msg1Initial.setGetParams(urlRequestParams); // url parameters // send the message, minus the value for the current parameter, and see how it // comes back. // Note: automatically follow redirects.. no need to look at any intermediate // responses. // this was only necessary for cookie-based session implementations sendAndReceive(msg1Initial); // if non-200 on the response for message 1, no point in continuing. Bale out. if (msg1Initial.getResponseHeader().getStatusCode() != HttpStatusCode.OK) { if (this.debugEnabled) log.debug("Got a non-200 response code [" + msg1Initial.getResponseHeader().getStatusCode() + "] when sending [" + msg1Initial.getRequestHeader().getURI() + "] with param [" + currentHtmlParameter.getName() + "] = NULL (possibly somewhere in the redirects)"); continue; } // now parse the HTML response for urls that contain the same parameter name, // and look at the values for that parameter // if no values are found for the parameter, then // 1) we are messing with the wrong field, or // 2) the app doesn't do sessions // either way, there is not much point in continuing to look at this field.. // parse out links in HTML (assume for a moment that all the URLs are in links) // this gives us a map of parameter value for the current parameter, to the // number of times it was encountered in links in the HTML SortedMap<String, Integer> parametersInHTMLURls = getParameterValueCountInHtml( msg1Initial.getResponseBody().toString(), currentHtmlParameter.getName(), isPseudoUrlParameter); if (this.debugEnabled) log.debug("The count of the various values of the [" + currentHtmlParameter.getName() + "] parameters in urls in the result of retrieving the url with a null value for parameter [" + currentHtmlParameter.getName() + "]: " + parametersInHTMLURls); if (parametersInHTMLURls.isEmpty()) { // setting the param to NULL did not cause any new values to be generated // for it in the output.. // so either.. // it is not a session field, or // it is a session field, but a session is only issued on authentication, // and this is not an authentication url // the app doesn't do sessions (etc) // either way, the parameter/url combo is not vulnerable, so continue with // the next parameter if (this.debugEnabled) log.debug("The URL parameter [" + currentHtmlParameter.getName() + "] was NOT set in any links in the response, when " + (isPseudoUrlParameter ? "pseudo/URL rewritten" : "") + " URL param [" + currentHtmlParameter.getName() + "] was set to NULL in the request, so it is likely not a session id field"); continue; // to the next parameter } else if (parametersInHTMLURls.size() == 1) { // the parameter was set to just one value in the output // so it's quite possible it is the session id field that we have been // looking for // caveat 1: check it is longer than 3 chars long, to remove false // positives.. // we assume here that a real session id will always be greater than 3 // characters long // caveat 2: the value we got back for the param must be different from the // value we // over-wrote with NULL (empty) in the first place, otherwise it is very // unlikely to // be a session id field possibleSessionIdIssuedForUrlParam = parametersInHTMLURls.firstKey(); // did we get back the same value we just nulled out in the original // request? // if so, use this to eliminate false positives, and to optimise. if (possibleSessionIdIssuedForUrlParam.equals(currentHtmlParameter.getValue())) { if (this.debugEnabled) log.debug((isPseudoUrlParameter ? "pseudo/URL rewritten" : "") + " URL param [" + currentHtmlParameter.getName() + "], when set to NULL, causes 1 distinct values to be set for it in URLs in the output, but the possible session id value [" + possibleSessionIdIssuedForUrlParam + "] is the same as the value we over-wrote with NULL. 'Sorry, kid. You got the gift, but it looks like you're waiting for something'"); continue; // to the next parameter } if (possibleSessionIdIssuedForUrlParam.length() > 3) { // raise an alert here on an exposed session id, even if it is not // subject to a session fixation vulnerability // log.info("The URL parameter ["+ currentHtmlParameter.getName() + "] // was set ["+ // parametersInHTMLURls.get(possibleSessionIdIssuedForUrlParam)+ "] // times to ["+ possibleSessionIdIssuedForUrlParam + "] in links in the // response, when "+ (isPseudoUrlParameter?"pseudo/URL rewritten":"")+ " // URL param ["+ currentHtmlParameter.getName() + "] was set to NULL in // the request. This likely indicates it is a session id field."); // pass the original param value here, not the new value, since we're // displaying the session id exposed in the original message String extraInfo = Constant.messages.getString( "ascanbeta.sessionidexposedinurl.alert.extrainfo", currentHtmlParameter.getType(), currentHtmlParameter.getName(), currentHtmlParameter.getValue()); String attack = Constant.messages .getString("ascanbeta.sessionidexposedinurl.alert.attack", (isPseudoUrlParameter ? "pseudo/URL rewritten " : "") + currentHtmlParameter.getType(), currentHtmlParameter.getName()); String vulnname = Constant.messages.getString("ascanbeta.sessionidexposedinurl.name"); String vulndesc = Constant.messages.getString("ascanbeta.sessionidexposedinurl.desc"); String vulnsoln = Constant.messages.getString("ascanbeta.sessionidexposedinurl.soln"); if (loginUrl) { extraInfo += ("\n" + Constant.messages .getString("ascanbeta.sessionidexposedinurl.alert.extrainfo.loginpage")); } // call bingo with some extra info, indicating that the alert is // not specific to Session Fixation, but has its own title and // description (etc) // the alert here is "Session id exposed in url", or words to that // effect. bingo(Alert.RISK_MEDIUM, Alert.CONFIDENCE_MEDIUM, vulnname, vulndesc, getBaseMsg().getRequestHeader().getURI().getURI(), currentHtmlParameter.getName(), attack, extraInfo, vulnsoln, getBaseMsg()); if (log.isDebugEnabled()) { String logMessage = MessageFormat.format( "An exposed session identifier has been found at " + "[{0}] URL [{1}] on {2} field: [{3}]", getBaseMsg().getRequestHeader().getMethod(), getBaseMsg().getRequestHeader().getURI().getURI(), (isPseudoUrlParameter ? "pseudo " : "") + currentHtmlParameter.getType(), currentHtmlParameter.getName()); log.debug(logMessage); } // Note: do NOT continue to the next field at this point.. // since we still need to check for Session Fixation. } else { if (this.debugEnabled) log.debug((isPseudoUrlParameter ? "pseudo/URL rewritten" : "") + " URL param [" + currentHtmlParameter.getName() + "], when set to NULL, causes 1 distinct values to be set for it in URLs in the output, but the possible session id value [" + possibleSessionIdIssuedForUrlParam + "] is too short to be a real session id."); continue; // to the next parameter } } else { // strange scenario: setting the param to null causes multiple different // values to be set for it in the output // it could still be a session parameter, but we assume it is *not* a // session id field // log it, but assume it is not a session id if (this.debugEnabled) log.debug((isPseudoUrlParameter ? "pseudo/URL rewritten" : "") + " URL param [" + currentHtmlParameter.getName() + "], when set to NULL, causes [" + parametersInHTMLURls.size() + "] distinct values to be set for it in URLs in the output. Assuming it is NOT a session id as a consequence. This could be a false negative"); continue; // to the next parameter } //////////////////////////////////////////////////////////////////////////////////////////// /// Message 2 - processing starts here //////////////////////////////////////////////////////////////////////////////////////////// // we now have a plausible session id field to play with, so set it to a // borrowed value. // ie: lets re-send the request, but add in the new (valid) session value that // was just issued. // the aim is then to see if it accepts the session without re-issuing the // session id (BAD, in some circumstances), // or if it issues a new session value (GOOD, in most circumstances) // and set the (modified) session for the second message // use a copy of msg2Initial, since it has already had the correct session // removed in the request.. // do NOT use msg2Initial itself, as this will cause both requests in the GUI to // show the modified data.. // finally send the second message, and see how it comes back. HttpMessage msg2Initial = msg1Initial.cloneRequest(); // set the parameter to the new session id value (in different manners, // depending on whether it is a real url param, or a pseudo url param) if (isPseudoUrlParameter) { // we need to "rewrite" (hack) the URL path to remove the pseudo url // parameter portion // id, we need to remove the ";jsessionid=<sessionid>" bit from the path // and replace it with ";jsessionid=" (ie, we nullify the possible "session" // parameter in the hope that a new session will be issued) // then we continue as usual to see if the URL is vulnerable to a Session // Fixation issue // Side note: quote the string to search for, and the replacement, so that // regex special characters are treated as literals String hackedUrl = requestUrl.replaceAll( Pattern.quote(";" + currentHtmlParameter.getName() + "=" + currentHtmlParameter.getValue()), Matcher.quoteReplacement(";" + currentHtmlParameter.getName() + "=" + possibleSessionIdIssuedForUrlParam)); if (this.debugEnabled) log.debug("Changing the pseudo URL parameter from [" + requestUrl + "]: [" + hackedUrl + "]"); // Note: the URL is not escaped msg2Initial.getRequestHeader().setURI(new URI(hackedUrl, false)); msg2Initial.setGetParams(msg1Initial.getUrlParams()); // restore the GET params } else { // do it via the normal url parameters TreeSet<HtmlParameter> urlRequestParams2 = msg2Initial.getUrlParams(); urlRequestParams2.add(new HtmlParameter(Type.url, currentHtmlParameter.getName(), possibleSessionIdIssuedForUrlParam)); msg2Initial.setGetParams(urlRequestParams2); // restore the GET params } // resend a copy of the initial message, but with the new valid session // parameter added in, to see if it is accepted // automatically follow redirects, which are irrelevant for the purposes of // testing URL parameters sendAndReceive(msg2Initial); // final result was non-200, no point in continuing. Bale out. if (msg2Initial.getResponseHeader().getStatusCode() != HttpStatusCode.OK) { if (this.debugEnabled) log.debug("Got a non-200 response code [" + msg2Initial.getResponseHeader().getStatusCode() + "] when sending [" + msg2Initial.getRequestHeader().getURI() + "] with a borrowed session (or by following a redirect) for param [" + currentHtmlParameter.getName() + "]"); continue; // next field! } // do the analysis on the parameters in link urls in the HTML output again to // see if the session id was regenerated SortedMap<String, Integer> parametersInHTMLURls2 = getParameterValueCountInHtml( msg2Initial.getResponseBody().toString(), currentHtmlParameter.getName(), isPseudoUrlParameter); if (this.debugEnabled) log.debug("The count of the various values of the [" + currentHtmlParameter.getName() + "] parameters in urls in the result of retrieving the url with a borrowed session value for parameter [" + currentHtmlParameter.getName() + "]: " + parametersInHTMLURls2); if (parametersInHTMLURls2.size() != 1) { // either no values, or multiple values, but not 1 value. For a session // that was regenerated, we would have expected to see // just 1 new value if (this.debugEnabled) log.debug("The HTML has spoken. [" + currentHtmlParameter.getName() + "] doesn't look like a session id field, because there are " + parametersInHTMLURls2.size() + " distinct values for this parameter in urls in the HTML output"); continue; } // there is but one value for this param in links in the HTML output. But is it // vulnerable to Session Fixation? Ie, is it the same parameter? String possibleSessionIdIssuedForUrlParam2 = parametersInHTMLURls2.firstKey(); if (possibleSessionIdIssuedForUrlParam2.equals(possibleSessionIdIssuedForUrlParam)) { // same sessionid used in the output.. so it is likely that we have a // SessionFixation issue.. // use the url param extrainfo message, which is specific to the case of url // parameters and url re-writing Session Fixation issue // pretty much everything else is generic to all types of Session Fixation // vulnerabilities String extraInfo = Constant.messages.getString( "ascanbeta.sessionfixation.alert.url.extrainfo", currentHtmlParameter.getName(), possibleSessionIdIssuedForUrlParam, possibleSessionIdIssuedForUrlParam2); String attack = Constant.messages.getString("ascanbeta.sessionfixation.alert.attack", (isPseudoUrlParameter ? "pseudo/URL rewritten " : "") + currentHtmlParameter.getType(), currentHtmlParameter.getName()); int risk = Alert.RISK_LOW; if (loginUrl) { extraInfo += ("\n" + Constant.messages .getString("ascanbeta.sessionfixation.alert.url.extrainfo.loginpage")); // login page, so higher risk risk = Alert.RISK_MEDIUM; } else { // not a login page.. lower risk risk = Alert.RISK_LOW; } bingo(risk, Alert.CONFIDENCE_MEDIUM, getBaseMsg().getRequestHeader().getURI().getURI(), currentHtmlParameter.getName(), attack, extraInfo, getBaseMsg()); logSessionFixation(getBaseMsg(), (isPseudoUrlParameter ? "pseudo " : "") + currentHtmlParameter.getType(), currentHtmlParameter.getName()); continue; // jump to the next iteration of the loop (ie, the next parameter) } else { // different sessionid used in the output.. so it is unlikely that we have a // SessionFixation issue.. // more likely that the Session is being re-issued for every single request, // or we have issues a login request, which // normally causes a session to be reissued if (this.debugEnabled) log.debug("The " + (isPseudoUrlParameter ? "pseudo/URL rewritten" : "") + " parameter [" + currentHtmlParameter.getName() + "] in url [" + getBaseMsg().getRequestHeader().getMethod() + "] [" + getBaseMsg().getRequestHeader().getURI() + "] changes with requests, and so it likely not vulnerable to Session Fixation"); } continue; // onto the next parameter } // end of the url parameter code. } // end of the for loop around the parameter list } catch (Exception e) { // Do not try to internationalise this.. we need an error message in any event.. // if it's in English, it's still better than not having it at all. log.error("An error occurred checking a url for Session Fixation issues", e); } }