Initial graduated contribution
diff --git a/bundles/org.eclipse.equinox.security.ui/.classpath b/bundles/org.eclipse.equinox.security.ui/.classpath
new file mode 100644
index 0000000..ce73933
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.4"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.equinox.security.ui/.project b/bundles/org.eclipse.equinox.security.ui/.project
new file mode 100644
index 0000000..3506a59
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.equinox.security.ui</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.equinox.security.ui/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.security.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..1bce9db
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,331 @@
+#Tue Jan 29 15:26:50 EST 2008
+eclipse.preferences.version=1
+instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=1000
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=error
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.3
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=false
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false
+org.eclipse.jdt.core.formatter.comment.format_line_comments=false
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=800
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
diff --git a/bundles/org.eclipse.equinox.security.ui/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.equinox.security.ui/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..416d090
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,59 @@
+#Tue Sep 18 13:56:07 EDT 2007
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_core
+formatter_settings_version=11
+instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=;
+org.eclipse.jdt.ui.ondemandthreshold=3
+org.eclipse.jdt.ui.staticondemandthreshold=99
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_variable_declarations_final=true
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=false
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/bundles/org.eclipse.equinox.security.ui/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.equinox.security.ui/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 0000000..bc8d37e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,3 @@
+#Thu Sep 13 15:23:29 EDT 2007
+eclipse.preferences.version=1
+resolve.requirebundle=false
diff --git a/bundles/org.eclipse.equinox.security.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.security.ui/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..b7d5ed0
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,33 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.equinox.security.ui;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Import-Package: org.eclipse.core.resources,
+ org.eclipse.core.runtime,
+ org.eclipse.core.runtime.jobs,
+ org.eclipse.osgi.service.resolver;version="1.2.0",
+ org.eclipse.osgi.service.security;version="1.0.0",
+ org.eclipse.osgi.util;version="1.1.0",
+ org.eclipse.swt,
+ org.eclipse.swt.events,
+ org.eclipse.swt.graphics,
+ org.eclipse.swt.layout,
+ org.eclipse.swt.widgets,
+ org.eclipse.ui.dialogs,
+ org.osgi.framework,
+ org.osgi.util.tracker;version="1.3.3"
+Require-Bundle: org.eclipse.equinox.security,
+ org.eclipse.ui
+Bundle-Activator: org.eclipse.equinox.internal.security.ui.Activator
+Export-Package: org.eclipse.equinox.internal.security.ui;x-internal:=true,
+ org.eclipse.equinox.internal.security.ui.nls;x-internal:=true,
+ org.eclipse.equinox.internal.security.ui.preferences;x-internal:=true,
+ org.eclipse.equinox.internal.security.ui.storage;x-internal:=true,
+ org.eclipse.equinox.internal.security.ui.wizard;x-internal:=true,
+ org.eclipse.equinox.security.ui.actions,
+ org.eclipse.equinox.security.ui.services
+Bundle-RequiredExecutionEnvironment: J2SE-1.4
+Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.equinox.security.ui/about.html b/bundles/org.eclipse.equinox.security.ui/about.html
new file mode 100644
index 0000000..4602330
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 2, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.security.ui/build.properties b/bundles/org.eclipse.equinox.security.ui/build.properties
new file mode 100644
index 0000000..7501eb3
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/build.properties
@@ -0,0 +1,20 @@
+###############################################################################
+# Copyright (c) 2005, 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ plugin.xml,\
+ .,\
+ plugin.properties,\
+ icons/,\
+ about.html
+src.includes = src/,\
+ about.html
diff --git a/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/green.GIF b/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/green.GIF
new file mode 100644
index 0000000..e8e295f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/green.GIF
Binary files differ
diff --git a/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/red.GIF b/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/red.GIF
new file mode 100644
index 0000000..c201c83
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/red.GIF
Binary files differ
diff --git a/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/signed_yes_tbl.gif b/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/signed_yes_tbl.gif
new file mode 100644
index 0000000..3a174cc
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/signed_yes_tbl.gif
Binary files differ
diff --git a/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/yellow.GIF b/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/yellow.GIF
new file mode 100644
index 0000000..799fd23
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/icons/full/obj16/yellow.GIF
Binary files differ
diff --git a/bundles/org.eclipse.equinox.security.ui/icons/titleAreaCert.gif b/bundles/org.eclipse.equinox.security.ui/icons/titleAreaCert.gif
new file mode 100644
index 0000000..c81e879
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/icons/titleAreaCert.gif
Binary files differ
diff --git a/bundles/org.eclipse.equinox.security.ui/plugin.properties b/bundles/org.eclipse.equinox.security.ui/plugin.properties
new file mode 100644
index 0000000..b1edb56
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/plugin.properties
@@ -0,0 +1,19 @@
+###############################################################################
+# Copyright (c) 2005, 2008 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+
+pluginName = Equinox Security Default UI
+providerName = Eclipse.org
+security = Security
+policy = Policy
+certificates = Certificates
+advanced = Advanced
+certificateFile = Certificate File
+certificateFileDescription = Import certificates into the platform.
diff --git a/bundles/org.eclipse.equinox.security.ui/plugin.xml b/bundles/org.eclipse.equinox.security.ui/plugin.xml
new file mode 100644
index 0000000..87f240f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/plugin.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin>
+
+ <extension point="org.eclipse.ui.preferencePages">
+ <page
+ name="%security"
+ class="org.eclipse.equinox.internal.security.ui.preferences.SecurityCategoryPage"
+ id="org.eclipse.equinox.security.ui.category">
+ </page>
+ </extension>
+
+ <extension point="org.eclipse.ui.preferencePages">
+ <page
+ name="%policy"
+ class="org.eclipse.equinox.internal.security.ui.preferences.PolicyPage"
+ id="org.eclipse.equinox.security.ui.policy"
+ category="org.eclipse.equinox.security.ui.category">
+ </page>
+ </extension>
+
+ <extension point="org.eclipse.ui.preferencePages">
+ <page
+ name="%certificates"
+ class="org.eclipse.equinox.internal.security.ui.preferences.CertificatesPage"
+ id="org.eclipse.equinox.security.ui.certificates"
+ category="org.eclipse.equinox.security.ui.category">
+ </page>
+ </extension>
+
+ <extension point="org.eclipse.ui.preferencePages">
+ <page
+ name="%advanced"
+ class="org.eclipse.equinox.internal.security.ui.preferences.AdvancedPage"
+ id="org.eclipse.equinox.security.ui.advanced"
+ category="org.eclipse.equinox.security.ui.category">
+ </page>
+ </extension>
+ <extension
+ point="org.eclipse.ui.importWizards">
+ <wizard
+ category="org.eclipse.ui.Basic"
+ class="org.eclipse.equinox.internal.security.ui.wizard.CertificateImportWizard"
+ icon="icons/full/obj16/signed_yes_tbl.gif"
+ id="org.eclipse.equinox.security.ui.importWizards.ImportWizard"
+ name="%certificateFile">
+ <description>
+ %certificateFileDescription
+ </description>
+ <selection class="org.eclipse.core.resources.IResource" />
+ </wizard>
+ </extension>
+
+ <!-- The default UI password provider -->
+ <extension
+ id="DefaultPasswordProvider"
+ point="org.eclipse.equinox.security.secureStorage">
+ <provider
+ class="org.eclipse.equinox.internal.security.ui.storage.DefaultPasswordProvider"
+ priority="2">
+ </provider>
+ </extension>
+
+</plugin>
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/Activator.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/Activator.java
new file mode 100644
index 0000000..124f27c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/Activator.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui;
+
+import java.security.Security;
+import java.util.Hashtable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.equinox.security.ui.services.AuthorizationManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.service.resolver.PlatformAdmin;
+import org.eclipse.osgi.service.security.AuthorizationEngine;
+import org.eclipse.osgi.service.security.TrustEngine;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.*;
+import org.osgi.util.tracker.ServiceTracker;
+
+// TBD change to use standard NLS mechanism and then switch to implement BundleActivator
+// TBD most of the strings in the message file are not used
+public class Activator extends AbstractUIPlugin {
+
+ public static final String PLUGIN_ID = "org.eclipse.equinox.security.ui"; //$NON-NLS-1$
+
+ // constants for services
+ private static final String PROP_TRUST_ENGINE = "osgi.signedcontent.trust.engine"; //$NON-NLS-1$
+ private static final String PROP_AUTHZ_ENGINE = "osgi.signedcontent.authorization.engine"; //$NON-NLS-1$
+ private static final String PROP_AUTHZ_MANAGER = "osgi.signedcontent.authorization.manager"; //$NON-NLS-1$
+
+ private static final String PROP_DEFAULT_SERVICE = "org.eclipse.osgi"; //$NON-NLS-1$
+
+ //service trackers
+ private static ServiceTracker trustEngineTracker;
+ private static ServiceTracker authzEngineTracker;
+ private static ServiceTracker authzManagerTracker;
+ private static ServiceTracker platformAdminTracker;
+
+ // The shared plug-in instance
+ private static Activator plugin;
+
+ // The bundle context
+ private static BundleContext bundleContext;
+ private ServiceRegistration defaultAuthzManagerReg;
+
+ public Activator() {
+ super();
+ }
+
+ /**
+ * Returns the bundle context.
+ */
+ public static BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Returns the symbolic name for this bundle.
+ */
+ public static String getSymbolicName() {
+ return plugin.getBundle().getSymbolicName();
+ }
+
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ bundleContext = context;
+ plugin = this;
+
+ // Register the default authorization manager
+ Hashtable properties = new Hashtable(7);
+ properties.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE));
+ properties.put(PROP_AUTHZ_MANAGER, PROP_DEFAULT_SERVICE);
+ defaultAuthzManagerReg = bundleContext.registerService(AuthorizationManager.class.getName(), new DefaultAuthorizationManager(), properties);
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ bundleContext = null;
+ plugin = null;
+
+ if (defaultAuthzManagerReg != null) {
+ defaultAuthzManagerReg.unregister();
+ defaultAuthzManagerReg = null;
+ }
+
+ if (authzEngineTracker != null) {
+ authzEngineTracker.close();
+ authzEngineTracker = null;
+ }
+
+ if (authzManagerTracker != null) {
+ authzManagerTracker.close();
+ authzManagerTracker = null;
+ }
+
+ if (platformAdminTracker != null) {
+ platformAdminTracker.close();
+ platformAdminTracker = null;
+ }
+ }
+
+ public static TrustEngine[] getTrustEngines() {
+ if (trustEngineTracker == null) {
+ String trustAuthorityProp = Security.getProperty(PROP_TRUST_ENGINE);
+ Filter filter = null;
+ if (trustAuthorityProp != null)
+ try {
+ filter = FrameworkUtil.createFilter("(&(" + Constants.OBJECTCLASS + "=" + TrustEngine.class.getName() + ")(" + PROP_TRUST_ENGINE + "=" + trustAuthorityProp + "))"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace();
+ // do nothing just use no filter TODO we may want to log something
+ }
+ if (filter != null) {
+ trustEngineTracker = new ServiceTracker(bundleContext, filter, null);
+ } else
+ trustEngineTracker = new ServiceTracker(bundleContext, TrustEngine.class.getName(), null);
+ trustEngineTracker.open();
+ }
+ Object[] services = trustEngineTracker.getServices();
+ if (services != null) {
+ TrustEngine[] engines = new TrustEngine[services.length];
+ System.arraycopy(services, 0, engines, 0, services.length);
+ return engines;
+ }
+ return new TrustEngine[0];
+ }
+
+ public static AuthorizationEngine getAuthorizationEngine() {
+ if (authzEngineTracker == null) {
+ String implProp = Security.getProperty(PROP_AUTHZ_ENGINE);
+ Filter filter = null;
+ if (implProp != null)
+ try {
+ filter = FrameworkUtil.createFilter("(&(" + Constants.OBJECTCLASS + "=" + AuthorizationEngine.class.getName() + ")(" + PROP_AUTHZ_ENGINE + "=" + implProp + "))"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$
+ } catch (InvalidSyntaxException e) {
+ //TODO:log the error
+ }
+ if (filter != null) {
+ authzEngineTracker = new ServiceTracker(Activator.getBundleContext(), filter, null);
+ } else {
+ authzEngineTracker = new ServiceTracker(Activator.getBundleContext(), AuthorizationEngine.class.getName(), null);
+ }
+ authzEngineTracker.open();
+ }
+ return (AuthorizationEngine) authzEngineTracker.getService();
+ }
+
+ public static AuthorizationManager getAuthorizationManager() {
+ if (authzManagerTracker == null) {
+ String implProp = Security.getProperty(PROP_AUTHZ_MANAGER);
+ Filter filter = null;
+ if (implProp != null)
+ try {
+ filter = FrameworkUtil.createFilter("(&(" + Constants.OBJECTCLASS + "=" + AuthorizationManager.class.getName() + ")(" + PROP_AUTHZ_MANAGER + "=" + implProp + "))"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$
+ } catch (InvalidSyntaxException e) {
+ //TODO:log the error
+ }
+ if (filter != null) {
+ authzManagerTracker = new ServiceTracker(Activator.getBundleContext(), filter, null);
+ } else {
+ authzManagerTracker = new ServiceTracker(Activator.getBundleContext(), AuthorizationManager.class.getName(), null);
+ }
+ authzManagerTracker.open();
+ }
+ return (AuthorizationManager) authzManagerTracker.getService();
+ }
+
+ public static PlatformAdmin getPlatformAdmin() {
+ if (platformAdminTracker == null) {
+ platformAdminTracker = new ServiceTracker(Activator.getBundleContext(), PlatformAdmin.class.getName(), null);
+ platformAdminTracker.open();
+ }
+ return (PlatformAdmin) platformAdminTracker.getService();
+ }
+
+ /**
+ * Get the workbench image with the given path relative to ICON_PATH.
+ * @param relativePath
+ * @return ImageDescriptor
+ */
+ public static ImageDescriptor getImageDescriptor(String relativePath) {
+ return imageDescriptorFromPlugin("org.eclipse.equinox.security.ui", "icons" + relativePath); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Logs a message.
+ * @param severity Either IStatus.INFO, IStatus.WARNING or IStatus.ERROR.
+ * @param key The key of the translated message in the resource bundle.
+ * @param args The arguments to pass to <code>MessageFormat.format</code>
+ * or <code>null</code> if the message has no arguments.
+ * @param throwable exception associated with this message or <code>null</code>.
+ */
+ public static void log(int severity, String key, Object args[], Throwable throwable) {
+ plugin.getLog().log(new Status(severity, getSymbolicName(), IStatus.OK, NLS.bind(key, args), throwable));
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/ConfirmationDialog.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/ConfirmationDialog.java
new file mode 100644
index 0000000..1a40329
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/ConfirmationDialog.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui;
+
+import java.security.cert.Certificate;
+import org.eclipse.equinox.internal.security.ui.wizard.CertificateViewer;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.*;
+
+public class ConfirmationDialog extends TitleAreaDialog {
+
+ public static final int YES = 100;
+ public static final int NO = 101;
+
+ private Certificate cert;
+
+ public ConfirmationDialog(Shell parentShell, Certificate cert) {
+ super(parentShell);
+ this.cert = cert;
+ }
+
+ protected Control createContents(Composite parent) {
+ return super.createContents(parent);
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ setTitle(SecurityUIMsg.CONFIRMATION_DIALOG_TITLE);
+ setMessage(SecurityUIMsg.CONFIRMATION_DIALOG_MSG);
+
+ Composite composite = new Composite(parent, SWT.None);
+ composite.setLayout(new FillLayout());
+
+ CertificateViewer certViewer = new CertificateViewer(composite);
+ certViewer.setCertificate(cert);
+
+ return composite;
+ }
+
+ protected void createButtonsForButtonBar(Composite parent) {
+ Button yesBtn = createButton(parent, YES, SecurityUIMsg.CONFIRMATION_DIALGO_YES, true);
+ yesBtn.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ setReturnCode(YES);
+ close();
+ }
+ });
+
+ Button noBtn = createButton(parent, NO, SecurityUIMsg.CONFIRMATION_DIALGO_NO, false);
+ noBtn.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ setReturnCode(NO);
+ close();
+ }
+ });
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/DefaultAuthorizationManager.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/DefaultAuthorizationManager.java
new file mode 100644
index 0000000..b2a257c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/DefaultAuthorizationManager.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.equinox.security.ui.services.AuthorizationManager;
+import org.eclipse.osgi.service.security.AuthorizationStatus;
+import org.eclipse.ui.IWorkbenchWindow;
+
+// 1. if there are disabled bundles, and if so, which ones, why, and whether they are fatal or warn
+// 2. when bundles are disabled, why and whether they are fatal or warn
+// 3. when bundles are enabled
+public class DefaultAuthorizationManager extends AuthorizationManager {
+
+ boolean enabled = (null != Activator.getAuthorizationEngine());
+
+ private int currentStatus = IStatus.OK;
+ private boolean needsAttention = false;
+
+ public DefaultAuthorizationManager() {
+ currentStatus = enabled ? Activator.getAuthorizationEngine().getStatus() : IStatus.OK;
+ }
+
+ public boolean isEnabled() {
+ return true;
+ }
+
+ public boolean needsAttention() {
+ return needsAttention; //TODO: make it happen
+ }
+
+ public IStatus getStatus() {
+ currentStatus = enabled ? Activator.getAuthorizationEngine().getStatus() : IStatus.OK;
+ return transformStatus(currentStatus);
+ }
+
+ public void displayManager(IWorkbenchWindow workbenchWindow) {
+ //TODO: manager UI
+ }
+
+ private IStatus transformStatus(int engineStatus) {
+ Status status = null;
+ switch (engineStatus) {
+ case AuthorizationStatus.OK :
+ status = new Status(IStatus.OK, Activator.getSymbolicName(), ""); //$NON-NLS-1$ //TODO: text
+ break;
+
+ case AuthorizationStatus.ERROR :
+ status = new Status(IStatus.ERROR, Activator.getSymbolicName(), ""); //$NON-NLS-1$ //TODO: text
+ break;
+
+ default :
+ status = null;
+ break;
+ }
+ return status;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/SecurityStatusControl.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/SecurityStatusControl.java
new file mode 100644
index 0000000..41510fc
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/SecurityStatusControl.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.equinox.security.ui.services.AuthorizationManager;
+import org.eclipse.jface.action.ControlContribution;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * This contribution item is used to create a visual cue that informs the
+ * user of bundles disabled in the system for signature validation reasons.
+ *
+ * It has the following functions:
+ * - Two levels of severity, represented by two distinct graphical icons
+ * - Visual notification when new user attention is required (e.g. throbbing)
+ * - An informational message when the user hovers over the icon
+ * - A right-click menu for contributing security related actions
+ *
+ * @since 3.4
+ */
+public class SecurityStatusControl extends ControlContribution {
+
+ private static final String IMAGE_PATH_OK = "/full/obj16/green.GIF"; //$NON-NLS-1$
+ private static final String IMAGE_PATH_ERROR = "/full/obj16/red.GIF"; //$NON-NLS-1$
+ private static final String IMAGE_PATH_DISABLED = "/full/obj16/red.GIF"; //$NON-NLS-1$
+ private static final String IMAGE_PATH_UNKNOWN = "/full/obj16/red.GIF"; //$NON-NLS-1$
+
+ /* the default id for this Item */
+ private static final String ID = "org.eclipse.ui.securityStatus"; //$NON-NLS-1$
+
+ private IWorkbenchWindow window;
+ private CLabel label;
+
+ private IconState currentState;
+
+ /**
+ * Creates the contribution item.
+ *
+ * @param window the window
+ */
+ public SecurityStatusControl(IWorkbenchWindow window) {
+ this(window, ID);
+ }
+
+ /**
+ * Creates the contribution item.
+ *
+ * @param window the window
+ * @param id the id
+ */
+ public SecurityStatusControl(IWorkbenchWindow window, String id) {
+ super(id);
+ Assert.isNotNull(window);
+ this.window = window;
+ this.currentState = getCurrentState();
+ }
+
+ private static IconState getCurrentState() {
+ AuthorizationManager mgr = Activator.getAuthorizationManager();
+ return new IconState(mgr.isEnabled(), mgr.getStatus(), mgr.needsAttention());
+ }
+
+ protected Control createControl(Composite parent) {
+
+ label = new CLabel(parent, SWT.NONE);
+ label.setImage(getIcon(currentState));
+ label.addMouseListener(new MouseListener() {
+ public void mouseDoubleClick(MouseEvent e) {
+ //TODO: handleActionInvoked();
+ }
+
+ public void mouseDown(MouseEvent e) {
+ //nothing yet
+ }
+
+ public void mouseUp(MouseEvent e) {
+ //nothing yet
+ }
+ });
+
+ Job updateJob = new Job(ID) {
+ public IStatus run(IProgressMonitor monitor) {
+ while (true) {
+ IconState newState = getCurrentState();
+ if (!currentState.equals(newState)) {
+ final Display display = getDisplay(window);
+ if (null != display)
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (!label.isDisposed()) {
+ Image oldIcon = label.getImage();
+ label.setImage(getIcon(currentState));
+ oldIcon.dispose();
+ }
+ }
+ });
+ currentState = newState;
+ }
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ return null;
+ }
+ };
+ updateJob.setSystem(true);
+ updateJob.setPriority(Job.DECORATE);
+ updateJob.schedule();
+
+ return label;
+ }
+
+ public void dispose() {
+ Image currentImage = label.getImage();
+ if (currentImage != null) {
+ currentImage.dispose();
+ }
+ label.dispose();
+ }
+
+ protected static Image getIcon(IconState iconState) {
+ Image returnValue = null;
+
+ if (iconState.isEnabled()) {
+ IStatus status = iconState.getStatus();
+ ImageDescriptor imgDesc = null;
+ switch (status.getSeverity()) {
+ case IStatus.OK :
+ imgDesc = Activator.getImageDescriptor(IMAGE_PATH_OK);
+ break;
+
+ case IStatus.ERROR :
+ imgDesc = Activator.getImageDescriptor(IMAGE_PATH_ERROR);
+ break;
+
+ default :
+ imgDesc = Activator.getImageDescriptor(IMAGE_PATH_UNKNOWN);
+ break;
+ }
+ returnValue = imgDesc.createImage();
+ //TODO: decorate for needsAttention
+ } else {
+ ImageDescriptor imgDesc = Activator.getImageDescriptor(IMAGE_PATH_DISABLED);
+ returnValue = imgDesc.createImage();
+ }
+ return returnValue;
+ }
+
+ private static Display getDisplay(IWorkbenchWindow window) {
+ if (null != window) {
+ Shell shell = window.getShell();
+ if (null != shell)
+ return shell.getDisplay();
+ }
+ return null;
+ }
+
+ private static class IconState {
+ boolean enabled;
+ boolean needsAttention;
+ IStatus status;
+
+ IconState(boolean enabled, IStatus status, boolean needsAttention) {
+ if (null == status)
+ throw new IllegalArgumentException();
+
+ this.enabled = enabled;
+ this.status = status;
+ this.needsAttention = needsAttention;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public boolean needsAttention() {
+ return needsAttention;
+ }
+
+ public IStatus getStatus() {
+ return status;
+ }
+
+ public boolean equals(Object another) {
+ boolean returnValue = false;
+ if (another instanceof IconState) {
+ if (enabled == ((IconState) another).enabled) {
+ if (needsAttention == ((IconState) another).needsAttention) {
+ if (status.equals(((IconState) another).getStatus())) {
+ returnValue = true;
+ }
+ }
+ }
+ }
+ return returnValue;
+ }
+
+ public int hashCode() {
+ return Boolean.valueOf(enabled).hashCode() + status.hashCode() + Boolean.valueOf(needsAttention).hashCode();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/SecurityUIMsg.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/SecurityUIMsg.java
new file mode 100644
index 0000000..e8da035
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/SecurityUIMsg.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others_
+ * All rights reserved_ This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1_0
+ * which accompanies this distribution, and is available at
+ * http://www_eclipse_org/legal/epl-v10_html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui;
+
+import org.eclipse.osgi.util.NLS;
+
+public class SecurityUIMsg extends NLS {
+
+ public static String IMPORT_FILE;
+ public static String WIZARD_SELECT_CERT_FROM_DROP_DOWN;
+ public static String WIZARD_BROWSE;
+
+ // confirmation dialog
+ public static String CONFIRMATION_DIALOG_TITLE;
+ public static String CONFIRMATION_DIALOG_MSG;
+ public static String CONFIRMATION_DIALGO_YES;
+ public static String CONFIRMATION_DIALGO_NO;
+
+ // msgs for certificate import wizard
+ public static String WIZARD_TITLE_FILE_SELECT;
+ public static String WIZARD_TITLE_MSG;
+ public static String WIZARD_NOT_VALID_CERT;
+ public static String WIZARD_ALIAS_NAME_FIELD;
+ public static String WIZARD_TARGET_TRUST_ENGINE;
+ public static String WIZARD_SELECT_FILE;
+ public static String WIZARD_SELECT_CERT;
+ public static String WIZARD_IMPORT_CONFIRMATION_TITLE;
+ public static String WIZARD_IMPORT_CONFIRMATION_MSG;
+ public static String WIZARD_ENGINE_SELECT_TITLE;
+ public static String WIZARD_ENGINE_SELECT_MSG;
+ public static String WIZARD_PAGE_ENGINE;
+ public static String WIZARD_PAGE_CERT_SELECT;
+ public static String WIZARD_PAGE_FILE_CERT_SELECT;
+
+ // msgs for required fields in the import wizard
+ public static String WIZARD_ERROR_CERT_REQUIRED;
+ public static String WIZARD_ERROR_ALIAS_REQUIRED;
+ public static String WIZARD_ERROR_ENGINE_REQUIRED;
+ public static String WIZARD_ERROR_ALL_REQUIRED;
+ public static String WIZARD_ERROR_NO_WRITE_ENGINE;
+ public static String WIZARD_FILE_NOT_FOUND;
+
+ public static String STR_CERT_VIEWER_FIELD;
+ public static String STR_CERT_VIEWER_VALUE;
+
+ // messages for category page
+ public static String CATPAGE_LABEL_POLICY;
+ public static String CATPAGE_LABEL_CERTIFICATES;
+ public static String CATPAGE_LABEL_ADVANCED;
+
+ // messages for default policy page
+ public static String POLPAGE_LABEL_SECTION;
+ public static String POLPAGE_LABEL_TITLE;
+ public static String POLPAGE_BUTTON_ALLOW_ANY;
+ public static String POLPAGE_BUTTON_ALLOW_ANY_SIGNED;
+ public static String POLPAGE_BUTTON_ALLOW_ONLY_TRUSTED;
+ public static String POLPAGE_BUTTON_ALLOW_EXPIRED;
+
+ // messages for default certificates page
+ public static String CERTPAGE_LABEL_TITLE;
+ public static String CERTPAGE_LABEL_LINK;
+ public static String CERTPAGE_TABLE_LABEL;
+ public static String CERTPAGE_TABLE_HEADER_ISSUEDTO;
+ public static String CERTPAGE_TABLE_HEADER_ISSUEDBY;
+ public static String CERTPAGE_TABLE_HEADER_PROVIDER;
+ public static String CERTPAGE_BUTTON_IMPORT;
+ public static String CERTPAGE_BUTTON_EXPORT;
+ public static String CERTPAGE_BUTTON_REMOVE;
+ public static String CERTPAGE_BUTTON_VIEW;
+ public static String CERTPAGE_ERROR_UNKNOWN_FORMAT;
+
+ //messages for advanced page
+ public static String ADVPAGE_LABEL_PROVIDER;
+ public static String ADVPAGE_LABEL_VERSION;
+ public static String ADVPAGE_LABEL_DESCRIPTION;
+ public static String ADVPAGE_LABEL_SERVICES;
+ public static String ADVPAGE_LABEL_LINK;
+ public static String ADVPAGE_LABEL_CLASS;
+ public static String ADVPAGE_LABEL_ALIASES;
+ public static String ADVPAGE_LABEL_ATTRIBUTES;
+
+ public static String CERTVIEW_LABEL_BASIC;
+ public static String CERTVIEW_LABEL_DETAILS;
+ public static String CERTVIEW_LABEL_VALIDITY_DATES;
+
+ public static String CERTPROP_X509_FIELD_VALUE;
+ public static String CERTPROP_X509_VERSION;
+ public static String CERTPROP_X509_SERIAL_NUM;
+ public static String CERTPROP_X509_VALID_FROM;
+ public static String CERTPROP_X509_VALID_TO;
+
+ public static String CERTPROP_X509_ISSUED_BY;
+ public static String CERTPROP_X509_ISSUED_TO;
+
+ public static String CERTPROP_X509_SIG_ALGO;
+ public static String CERTPROP_X509_KEY_USAGE;
+ public static String CERTPROP_X509_SUB_ALT_NAMES;
+ public static String CERTPROP_X509_NAME_CNSTRNTS;
+ public static String CERTPROP_X509_CRL_DSTRB_PNTS;
+ public static String CERTPROP_X509_CERT_POLICIES;
+ public static String CERTPROP_X509_BASIC_CNSTRNTS;
+ public static String CERTPROP_X509_THMBPRINT_ALGO;
+ public static String CERTPROP_X509_THMBPRINT;
+ public static String CERTPROP_X509_THMBPRINTX509_PUBKEY_INFO;
+ public static String CERTPROP_X509_THMBPRINTX509_SUBKEY_ID;
+ public static String CERTPROP_X509_POLICY_CNSTRNTS;
+ public static String CERTPROP_X509_AUTH_KEY_ID;
+ public static String CERTPROP_X509_EXKEY_USAGE;
+
+ // X509 Certificate Viewer Labels and data items
+ public static String CERTVAL_DEFAULTDIGESTALGO;
+ public static String CERTVAL_VERSION;
+ public static String CERTVAL_UNDEFINED;
+ public static String LABEL_KEYUSAGE_DIGITALSIGNATURE;
+ public static String LABEL_KEYUSAGE_NONREPUDIATION;
+ public static String LABEL_KEYUSAGE_KEYENCIPHERMENT;
+ public static String LABEL_KEYUSAGE_DATAENCIPHERMENT;
+ public static String LABEL_KEYUSAGE_KEYAGREEMENT;
+ public static String LABEL_KEYUSAGE_CERTSIGN;
+ public static String LABEL_KEYUSAGE_CRLSIGN;
+ public static String LABEL_KEYUSAGE_ENCIPHERONLY;
+ public static String LABEL_KEYUSAGE_DECIPHERONLY;
+ public static String LABEL_NAMECONSTRAINTS_PERMITTED;
+ public static String LABEL_NAMECONSTRAINTS_EXCLUDED;
+ public static String LABEL_NAMECONSTRAINTS_ORGANIZATION;
+ public static String LABEL_NAMECONSTRAINTS_ISCA;
+ public static String LABEL_NAMECONSTRAINTS_PATHLENGTH;
+ public static String LABEL_NAMECONSTRAINTS_PATHLENGTH_UNLIMITED;
+ public static String LABEL_NAMECONSTRAINTS_NOTCA;
+
+ // These map to specific Extended Key Usage OIDs
+ // Not currently used
+ public static String LABEL_EXTKEYUSAGE_SERVERAUTH;
+ public static String LABEL_EXTKEYUSAGE_CLIENTAUTH;
+ public static String LABEL_EXTKEYUSAGE_CODESIGNING;
+ public static String LABEL_EXTKEYUSAGE_EMAILPROTECTION;
+ public static String LABEL_EXTKEYUSAGE_IPSEC_ENDENTITY;
+ public static String LABEL_EXTKEYUSAGE_IPSEC_TUNNEL;
+ public static String LABEL_EXTKEYUSAGE_IPSEC_USER;
+ public static String LABEL_EXTKEYUSAGE_TIMESTAMP;
+ // End not currently used
+
+ public static String X500_LABEL_CN;
+ public static String X500_LABEL_O;
+ public static String X500_LABEL_OU;
+ public static String X500_LABEL_C;
+ public static String X500_LABEL_ST;
+ public static String X500_LABEL_L;
+ public static String X500_LABEL_STREET;
+
+ // NLS stuff
+ private static final String BUNDLE_PACKAGE = "org.eclipse.equinox.internal.security.ui"; //$NON-NLS-1$
+ private static final String BUNDLE_FILENAME = "SecurityUIMsg"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = BUNDLE_PACKAGE + "." + BUNDLE_FILENAME; //$NON-NLS-1$
+
+ static {
+ NLS.initializeMessages(BUNDLE_NAME, SecurityUIMsg.class);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/SecurityUIMsg.properties b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/SecurityUIMsg.properties
new file mode 100644
index 0000000..0bfdff5
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/SecurityUIMsg.properties
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+IMPORT_FILE = Import file
+
+CONFIRMATION_DIALOG_TITLE=Confirmation
+CONFIRMATION_DIALOG_MSG=Are you sure to remove the following certificate?
+CONFIRMATION_DIALGO_YES=Yes
+CONFIRMATION_DIALGO_NO=NO
+
+WIZARD_TITLE_FILE_SELECT=Select a file w/ .p7b, .cer or .der file.
+WIZARD_TITLE_MSG=Select a certificate, fill out the alias name, and select a target engine
+WIZARD_NOT_VALID_CERT=Not a valid certificate!
+WIZARD_SELECT_CERT=Select a certificate
+WIZARD_SELECT_CERT_FROM_DROP_DOWN=Please select a certificate from the drop down
+
+WIZARD_FILE_NOT_FOUND=The file: {0} is not found!
+WIZARD_ALIAS_NAME_FIELD=Alias Name:
+WIZARD_TARGET_TRUST_ENGINE=Target engine:
+WIZARD_SELECT_FILE=Select a file
+WIZARD_BROWSE=Browse
+
+WIZARD_PAGE_ENGINE=Select Trust Engine
+WIZARD_PAGE_CERT_SELECT=Select a cert file
+WIZARD_PAGE_FILE_CERT_SELECT=Select a certificate file
+WIZARD_IMPORT_CONFIRMATION_TITLE=Confirmation
+WIZARD_IMPORT_CONFIRMATION_MSG=You selected the following cert and trust engine
+WIZARD_ENGINE_SELECT_TITLE=Certificate store information
+WIZARD_ENGINE_SELECT_MSG=Please enter the alias name and select a trust engine
+WIZARD_ERROR_CERT_REQUIRED = Must select a certificate file!
+WIZARD_ERROR_ALIAS_REQUIRED = Must give a alias for the certificate!
+WIZARD_ERROR_ENGINE_REQUIRED = Must select a target trust engine!
+WIZARD_ERROR_ALL_REQUIRED = Must complete all the fields!
+WIZARD_ERROR_NO_WRITE_ENGINE = There is no a writable trust engine!
+
+# org.eclipse.equinox.internal.security.ui.wizard
+STR_CERT_VIEWER_FIELD=Field
+STR_CERT_VIEWER_VALUE=Value
+
+
+CATPAGE_LABEL_POLICY = See <a>''{0}''</a> to manage policy settings applied to application code
+CATPAGE_LABEL_CERTIFICATES = See <a>''{0}''</a> to manage security certificates
+CATPAGE_LABEL_ADVANCED = See <a>''{0}''</a> to view advanced security configuration
+
+POLPAGE_LABEL_SECTION = Loading code
+POLPAGE_LABEL_TITLE = Manage policy applied to application code (UNDER CONSTRUCTION)
+POLPAGE_BUTTON_ALLOW_ANY = Allow any signed or unsigned application code
+POLPAGE_BUTTON_ALLOW_ANY_SIGNED = Allow any signed application code
+POLPAGE_BUTTON_ALLOW_ONLY_TRUSTED = Allow only signed and trusted application code
+POLPAGE_BUTTON_ALLOW_EXPIRED = Allow application code from signers with expired certificates
+
+CERTPAGE_LABEL_TITLE = Manage security certificates (UNDER CONSTRUCTION)
+CERTPAGE_LABEL_LINK = <a>Manage trust repositories...</a>
+CERTPAGE_TABLE_LABEL = Installed certificates:
+CERTPAGE_TABLE_HEADER_ISSUEDTO = Issued to:
+CERTPAGE_TABLE_HEADER_ISSUEDBY = Issued by:
+CERTPAGE_TABLE_HEADER_PROVIDER = Provider
+CERTPAGE_BUTTON_IMPORT = &Import...
+CERTPAGE_BUTTON_EXPORT = &Export...
+CERTPAGE_BUTTON_REMOVE = &Remove
+CERTPAGE_BUTTON_VIEW = &View...
+CERTPAGE_ERROR_UNKNOWN_FORMAT = Unknown format
+
+ADVPAGE_LABEL_PROVIDER = Provider:
+ADVPAGE_LABEL_VERSION = Version:
+ADVPAGE_LABEL_DESCRIPTION = Description:
+ADVPAGE_LABEL_SERVICES = Available services:
+ADVPAGE_LABEL_LINK = <a>Manage provider list...</a>
+ADVPAGE_LABEL_CLASS = Class:
+ADVPAGE_LABEL_ALIASES = Aliases:
+ADVPAGE_LABEL_ATTRIBUTES = Attributes
+
+CERTVIEW_LABEL_BASIC = General
+CERTVIEW_LABEL_DETAILS = Details
+CERTVIEW_LABEL_VALIDITY_DATES = Validity Dates
+
+CERTPROP_X509_FIELD_VALUE = Field Value
+CERTPROP_X509_VERSION = Version
+CERTPROP_X509_SERIAL_NUM = Serial Number
+CERTPROP_X509_VALID_FROM = Valid From
+CERTPROP_X509_VALID_TO = Valid Until
+
+CERTPROP_X509_ISSUED_BY = Issued by
+CERTPROP_X509_ISSUED_TO = Issued to
+
+CERTPROP_X509_SIG_ALGO = Signature Algorithm
+CERTPROP_X509_KEY_USAGE = Key Usage
+CERTPROP_X509_SUB_ALT_NAMES = Subject Alternate Names
+CERTPROP_X509_NAME_CNSTRNTS = NameConstraints
+CERTPROP_X509_CRL_DSTRB_PNTS = CRL Distribution Points
+CERTPROP_X509_CERT_POLICIES = Certificate Policies
+CERTPROP_X509_BASIC_CNSTRNTS = Basic Constraints
+CERTPROP_X509_THMBPRINT_ALGO = Thumbprint Algorithm
+CERTPROP_X509_THMBPRINT = Thumbprint
+CERTPROP_X509_THMBPRINTX509_PUBKEY_INFO = Public Key Info
+CERTPROP_X509_THMBPRINTX509_SUBKEY_ID = Subject Key Identifier
+CERTPROP_X509_POLICY_CNSTRNTS = Policy Constraints
+CERTPROP_X509_AUTH_KEY_ID = Authority Key Identifier
+CERTPROP_X509_EXKEY_USAGE = Extended Key Usage
+
+## X509 Certificate Viewer Labels and data items
+CERTVAL_DEFAULTDIGESTALGO = SHA-1
+CERTVAL_VERSION = V{0}
+CERTVAL_UNDEFINED = <Not Defined>
+LABEL_KEYUSAGE_DIGITALSIGNATURE = digitalSignature
+LABEL_KEYUSAGE_NONREPUDIATION = nonRepudiation
+LABEL_KEYUSAGE_KEYENCIPHERMENT = keyEncipherment
+LABEL_KEYUSAGE_DATAENCIPHERMENT = dataEncipherment
+LABEL_KEYUSAGE_KEYAGREEMENT = keyAgreement
+LABEL_KEYUSAGE_CERTSIGN = keyCertSign
+LABEL_KEYUSAGE_CRLSIGN = cRLSign
+LABEL_KEYUSAGE_ENCIPHERONLY = encipherOnly
+LABEL_KEYUSAGE_DECIPHERONLY = decipherOnly
+LABEL_NAMECONSTRAINTS_PERMITTED = Permitted:
+LABEL_NAMECONSTRAINTS_EXCLUDED = Excluded:
+LABEL_NAMECONSTRAINTS_ORGANIZATION = Organization :
+LABEL_NAMECONSTRAINTS_ISCA = CA Certificate
+LABEL_NAMECONSTRAINTS_PATHLENGTH = CA certificate (max path length = {0} )
+LABEL_NAMECONSTRAINTS_PATHLENGTH_UNLIMITED = "unlimited"
+LABEL_NAMECONSTRAINTS_NOTCA = Not a CA certificate
+
+## These map to specific Extended Key Usage OIDs
+## Not currently used
+LABEL_EXTKEYUSAGE_SERVERAUTH = Server Authentication
+LABEL_EXTKEYUSAGE_CLIENTAUTH = Client Authentication
+LABEL_EXTKEYUSAGE_CODESIGNING = Code signing
+LABEL_EXTKEYUSAGE_EMAILPROTECTION = Email Protection
+LABEL_EXTKEYUSAGE_IPSEC_ENDENTITY = IPSec End System
+LABEL_EXTKEYUSAGE_IPSEC_TUNNEL = IPSec Tunnel
+LABEL_EXTKEYUSAGE_IPSEC_USER = IPSec User
+LABEL_EXTKEYUSAGE_TIMESTAMP = Time Stamping
+## End not currently used
+
+X500_LABEL_CN = Common Name
+X500_LABEL_O = Organization
+X500_LABEL_OU = Organizational Unit
+X500_LABEL_C = Country
+X500_LABEL_ST = State
+X500_LABEL_L = Locale
+X500_LABEL_STREET = Street
+
+
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X500PrincipalHelper.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X500PrincipalHelper.java
new file mode 100644
index 0000000..431b987
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X500PrincipalHelper.java
@@ -0,0 +1,276 @@
+/*******************************************************************************
+ * Copyright (c) 2008, Jay Rosenthal
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Jay Rosenthal - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.security.ui;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * X500PrincipalHelper
+ * <p>
+ * Helper class to extract pieces (attributes) of an X500Principal object for display
+ * in the UI.
+ * <p>
+ * This helper uses the X500Principal.RFC2253 format of X500Principal.getname() to parse an X500Principal name
+ * into it's component parts.
+ * <p>
+ * In principals which contain multiple occurrences of the same attribute,the default for all the methods
+ * is to return the most significant (first) attribute found.
+ *
+ */
+
+public class X500PrincipalHelper {
+ public static int LEASTSIGNIFICANT = 0;
+ public static int MOSTSIGNIFICANT = 1;
+
+ public final static String attrCN = "CN"; //$NON-NLS-1$
+ public final static String attrOU = "OU"; //$NON-NLS-1$
+ public final static String attrO = "O"; //$NON-NLS-1$
+ public final static String attrC = "C"; //$NON-NLS-1$
+ public final static String attrL = "L"; //$NON-NLS-1$
+ public final static String attrST = "ST"; //$NON-NLS-1$
+ public final static String attrSTREET = "STREET";//$NON-NLS-1$
+ public final static String attrEMAIL = "EMAILADDRESS"; //$NON-NLS-1$
+ public final static String attrUID = "UID"; //$NON-NLS-1$
+
+ ArrayList rdnNameArray = new ArrayList();
+
+ private final static String attrTerminator = "="; //$NON-NLS-1$
+
+ public X500PrincipalHelper() {
+ // Do nothing constructor..
+ // Wont be useful unless setPrincipal is called...
+ }
+
+ public X500PrincipalHelper(X500Principal principal) {
+ parseDN(principal.getName(X500Principal.RFC2253));
+ }
+
+ /**
+ * Set the X500Principal name object to be parsed.
+ * <p>
+ * @param principal - X500Principal
+ */
+ public void setPrincipal(X500Principal principal) {
+ parseDN(principal.getName(X500Principal.RFC2253));
+ }
+
+ /**
+ * Gets the most significant common name (CN) attribute from the given
+ * X500Principal object.
+ * For names that contains multiple attributes of this type. The first
+ * (most significant) one will be returned
+ * <p>
+ * @return the Most significant common name attribute.
+ *
+ */
+ public String getCN() {
+ return findPart(attrCN);
+ }
+
+ /**
+ * Gets the most significant Organizational Unit (OU) attribute from the given
+ * X500Principal object.
+ * For names that contains multiple attributes of this type. The first
+ * (most significant) one will be returned
+ * <p>
+ *
+ * @return the Most significant OU attribute.
+ *
+ */
+
+ public String getOU() {
+ return findPart(attrOU);
+
+ }
+
+ /**
+ * Gets the most significant Organization (O) attribute from the given
+ * X500Principal object.
+ * For names that contains multiple attributes of this type. The first
+ * (most significant) one will be returned
+ * <p>
+ *
+ * @return the Most significant O attribute.
+ *
+ */
+
+ public String getO() {
+ return findPart(attrO);
+
+ }
+
+ /**
+ * Gets the Country (C) attribute from the given
+ * X500Principal object.
+ * <p>
+ *
+ * @return the C attribute.
+ *
+ */
+ public String getC() {
+ return findPart(attrC);
+ }
+
+ /**
+ * Gets the Locale (L) attribute from the given
+ * X500Principal object.
+ * <p>
+ *
+ * @return the L attribute.
+ *
+ */
+ public String getL() {
+ return findPart(attrL);
+ }
+
+ /**
+ * Gets the State (ST) attribute from the given
+ * X500Principal object.
+ * <p>
+ *
+ * @return the ST attribute.
+ *
+ */
+ public String getST() {
+ return findPart(attrST);
+ }
+
+ /**
+ * Gets the Street (STREET) attribute from the given
+ * X500Principal object.
+ * <p>
+ *
+ * @return the STREET attribute.
+ *
+ */
+ public String getSTREET() {
+ return findPart(attrSTREET);
+ }
+
+ /**
+ * Gets the Email Address (EMAILADDRESS) attribute from the given
+ * X500Principal object.
+ * <p>
+ *
+ * @return the EMAILADDRESS attribute.
+ *
+ */
+ public String getEMAILDDRESS() {
+ return findPart(attrEMAIL);
+ }
+
+ public String getUID() {
+ return findPart(attrUID);
+ }
+
+ /**
+ * Derived From: org.eclipse.osgi.internal.verifier - DNChainMatching.java
+ *
+ * Takes a distinguished name in canonical form and fills in the rdnArray
+ * with the extracted RDNs.
+ *
+ * @param dn the distinguished name in canonical form.
+ * @throws IllegalArgumentException if a formatting error is found.
+ */
+ private void parseDN(String dn) throws IllegalArgumentException {
+ int startIndex = 0;
+ char c = '\0';
+ ArrayList nameValues = new ArrayList();
+
+ // Clear the existing array, in case this instance is being re-used
+ rdnNameArray.clear();
+
+ while (startIndex < dn.length()) {
+ int endIndex;
+ for (endIndex = startIndex; endIndex < dn.length(); endIndex++) {
+ c = dn.charAt(endIndex);
+ if (c == ',' || c == '+')
+ break;
+ if (c == '\\') {
+ endIndex++; // skip the escaped char
+ }
+ }
+
+ if (endIndex > dn.length())
+ throw new IllegalArgumentException("unterminated escape " + dn); //$NON-NLS-1$
+
+ nameValues.add(dn.substring(startIndex, endIndex));
+
+ if (c != '+') {
+ rdnNameArray.add(nameValues);
+ if (endIndex != dn.length())
+ nameValues = new ArrayList();
+ else
+ nameValues = null;
+ }
+ startIndex = endIndex + 1;
+ }
+ if (nameValues != null) {
+ throw new IllegalArgumentException("improperly terminated DN " + dn); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns an ArrayList containing all the values for the given attribute identifier.
+ * <p>
+ * @param attributeID String containing the X500 name attribute whose values are to be
+ * returned
+ * @return ArrayList containing the string values of the requested attribute. Values are in
+ * the order they occur. May be empty.
+ *
+ */
+ public ArrayList getAllValues(String attributeID) {
+ ArrayList retList = new ArrayList();
+ String searchPart = attributeID + attrTerminator;
+
+ for (Iterator iter = rdnNameArray.iterator(); iter.hasNext();) {
+ ArrayList nameList = (ArrayList) iter.next();
+ String namePart = (String) nameList.get(0);
+
+ if (namePart.startsWith(searchPart)) {
+ // Return the string starting after the ID string and the = sign that follows it.
+ retList.add(namePart.toString().substring(searchPart.length()));
+ }
+ }
+
+ return retList;
+
+ }
+
+ private String findPart(String attributeID) {
+ return findSignificantPart(attributeID, MOSTSIGNIFICANT);
+ }
+
+ private String findSignificantPart(String attributeID, int significance) {
+ String retNamePart = null;
+ String searchPart = attributeID + attrTerminator;
+
+ for (Iterator iter = rdnNameArray.iterator(); iter.hasNext();) {
+ ArrayList nameList = (ArrayList) iter.next();
+ String namePart = (String) nameList.get(0);
+
+ if (namePart.startsWith(searchPart)) {
+ // Return the string starting after the ID string and the = sign that follows it.
+ retNamePart = namePart.toString().substring(searchPart.length());
+ // By definition the first one is most significant
+ if (significance == MOSTSIGNIFICANT)
+ break;
+ }
+ }
+
+ return retNamePart;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateAttribute.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateAttribute.java
new file mode 100644
index 0000000..914f982
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateAttribute.java
@@ -0,0 +1,52 @@
+package org.eclipse.equinox.internal.security.ui;
+
+/**
+ * Used by the X509CertificateAttributeContentProvider.
+ *
+ * Objects of this class contain a decomposition of an attribute in an X509 certificate so it can be
+ * displayed in the UI.
+ *
+ */
+public class X509CertificateAttribute {
+ // Description of the field
+ // NOTE: This will show in the UI so it should be loaded from a translatable properties file.
+ private String fieldDescription;
+
+ // A String representation of the value of the field. May have undergone some
+ // transformation to make it "pretty" in the UI
+ private String stringVal;
+
+ // The raw data object from inside the certificate. Most likely whatever object the getter method
+ // for the field returns.
+ private Object rawValue;
+
+ public X509CertificateAttribute(String propDescription, String StringVal, Object objValue) {
+ super();
+ fieldDescription = propDescription;
+ stringVal = StringVal;
+ rawValue = objValue;
+ }
+
+ public X509CertificateAttribute(String propDescription, String StringVal) {
+ super();
+ fieldDescription = propDescription;
+ stringVal = StringVal;
+ rawValue = null;
+ }
+
+ public String getDescription() {
+ return fieldDescription;
+ }
+
+ public String getStringValue() {
+ return stringVal;
+ }
+
+ public Object getValue() {
+ if (rawValue == null) {
+ return stringVal;
+ }
+ return rawValue;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateAttributeContentProvider.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateAttributeContentProvider.java
new file mode 100644
index 0000000..cd7eba8
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateAttributeContentProvider.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * Copyright (c) 2008, Jay Rosenthal
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Jay Rosenthal - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.security.ui;
+
+import java.security.MessageDigest;
+import java.security.PublicKey;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.util.*;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * X509CertificateAttributeContentProvider
+ * Structured content provided for an <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/security/cert/X509Certificate.html">X509Certificate </a>
+ * object.
+ * <p>
+ * Currently this only supports the attributes exposed directly by X509Certificate. Some commonly used extensions
+ * may not be displayed. Contributions and enhancements are welcomed.
+ *
+ */
+public class X509CertificateAttributeContentProvider implements IStructuredContentProvider {
+ private ArrayList elements = new ArrayList();
+ private Viewer viewer = null;
+ private static String listDelim = ", "; //$NON-NLS-1$
+
+ private static final DateFormat _df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.FULL);
+
+ // TODO - This is a bit ugly but gets the job done... Maybe this should be a class of it's own ??
+ private static String keyUsageStrings[] = {SecurityUIMsg.LABEL_KEYUSAGE_DIGITALSIGNATURE, SecurityUIMsg.LABEL_KEYUSAGE_NONREPUDIATION, SecurityUIMsg.LABEL_KEYUSAGE_KEYENCIPHERMENT, SecurityUIMsg.LABEL_KEYUSAGE_DATAENCIPHERMENT, SecurityUIMsg.LABEL_KEYUSAGE_KEYAGREEMENT, SecurityUIMsg.LABEL_KEYUSAGE_CERTSIGN, SecurityUIMsg.LABEL_KEYUSAGE_CRLSIGN, SecurityUIMsg.LABEL_KEYUSAGE_ENCIPHERONLY, SecurityUIMsg.LABEL_KEYUSAGE_DECIPHERONLY};
+
+ public X509CertificateAttributeContentProvider() {
+ super();
+
+ }
+
+ public Object[] getElements(Object inputElement) {
+ return elements.toArray();
+ }
+
+ public void dispose() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setSelection(X509Certificate curCert) {
+
+ inputChanged(viewer, null, curCert);
+
+ if (viewer != null)
+ viewer.refresh();
+ }
+
+ public void clear(boolean refresh) {
+ elements.clear();
+ if (refresh && viewer != null)
+ viewer.refresh();
+ }
+
+ public void clear() {
+ clear(true);
+ }
+
+ public void inputChanged(Viewer aViewer, Object oldInput, Object newInput) {
+ viewer = aViewer;
+ clear(false); // clear the viewer.
+
+ // Be safe ... check the input
+ if (newInput instanceof X509Certificate) {
+
+ X509Certificate theCert = (X509Certificate) newInput;
+
+ X509CertificateAttribute ver = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_VERSION, new Integer(theCert.getVersion()).toString());
+ elements.add(ver);
+
+ X509CertificateAttribute serialNum = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_SERIAL_NUM, theCert.getSerialNumber().toString());
+ elements.add(serialNum);
+
+ X509CertificateAttribute validFrom = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_VALID_FROM, _df.format(theCert.getNotBefore()), theCert.getNotBefore());
+ elements.add(validFrom);
+
+ X509CertificateAttribute validTo = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_VALID_TO, _df.format(theCert.getNotAfter()), theCert.getNotAfter());
+ elements.add(validTo);
+
+ X509CertificateAttribute issuedBy = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_ISSUED_BY, theCert.getIssuerX500Principal().getName(), theCert.getIssuerX500Principal());
+ elements.add(issuedBy);
+
+ X509CertificateAttribute IssuedToItem = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_ISSUED_TO, theCert.getSubjectX500Principal().getName(), theCert.getSubjectX500Principal());
+ elements.add(IssuedToItem);
+
+ X509CertificateAttribute sigAlgoItem = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_SIG_ALGO, theCert.getSigAlgName());
+ elements.add(sigAlgoItem);
+
+ boolean keyUsagesArray[] = theCert.getKeyUsage();
+ StringBuffer keyUsages = new StringBuffer();
+ //
+ // Only set the string field, If we got some data
+ if (keyUsagesArray != null && keyUsagesArray.length > 0) {
+ for (int i = 0; i < keyUsagesArray.length; i++) {
+ if (keyUsagesArray[i])
+ keyUsages.append(keyUsageStrings[i] + listDelim);
+ }
+
+ X509CertificateAttribute keyUsage = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_KEY_USAGE, (keyUsages.toString()).substring(0, keyUsages.length() - 2), theCert.getKeyUsage());
+ elements.add(keyUsage);
+ }
+
+ /*
+ * Thumbprint is not actually "in" the certificate. It is computed on the fly...
+ */
+ X509CertificateAttribute thumbPrintItem = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_THMBPRINT, getThumbprint(theCert, "SHA1")); //$NON-NLS-1$
+ elements.add(thumbPrintItem);
+
+ PublicKey pubKey = theCert.getPublicKey();
+ X509CertificateAttribute pubKeyInfoItem = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_THMBPRINTX509_PUBKEY_INFO, getHex(pubKey.getEncoded()));
+ elements.add(pubKeyInfoItem);
+
+ Collection subAltNamesVctr;
+ try {
+ subAltNamesVctr = theCert.getSubjectAlternativeNames();
+
+ // StringBuffer bfrSubAltNames = new StringBuffer();
+ if (subAltNamesVctr != null && subAltNamesVctr.size() > 0) {
+ // TODO - Make alt names into a displayable list...
+
+ // For now just display that they exist..
+ X509CertificateAttribute subAltItem = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_SUB_ALT_NAMES, "Has Subject Alternate Names" /*bfrSubAltNames.toString()*/, theCert.getSubjectAlternativeNames()); //$NON-NLS-1$
+ elements.add(subAltItem);
+ }
+ } catch (CertificateParsingException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ int basicCnstrnts = theCert.getBasicConstraints();
+ Integer basicConstraint = new Integer(basicCnstrnts);
+ StringBuffer basicCnstrntsBfr = new StringBuffer();
+ if (basicCnstrnts == -1) {
+ // Not a CA
+ basicCnstrntsBfr.append(SecurityUIMsg.LABEL_NAMECONSTRAINTS_NOTCA + listDelim);
+ } else {
+ basicCnstrntsBfr.append(SecurityUIMsg.LABEL_NAMECONSTRAINTS_ISCA + listDelim);
+ if (basicCnstrnts == Integer.MAX_VALUE) {
+ // MAX_VALUE means "no limit to the allowed length of the certification path."
+ basicCnstrntsBfr.append(NLS.bind(SecurityUIMsg.LABEL_NAMECONSTRAINTS_PATHLENGTH, new Object[] {SecurityUIMsg.LABEL_NAMECONSTRAINTS_PATHLENGTH_UNLIMITED}) + listDelim);
+ } else {
+ basicCnstrntsBfr.append(NLS.bind(SecurityUIMsg.LABEL_NAMECONSTRAINTS_PATHLENGTH, new Object[] {basicConstraint}) + listDelim);
+ }
+ }
+
+ X509CertificateAttribute basicConstraints = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_BASIC_CNSTRNTS, (basicCnstrntsBfr.toString()).substring(0, basicCnstrntsBfr.length() - 2), basicConstraint);
+ elements.add(basicConstraints);
+
+ List exKeyUsg;
+ try {
+ exKeyUsg = theCert.getExtendedKeyUsage();
+ StringBuffer exKeyUsgBfr = new StringBuffer();
+ if (exKeyUsg != null && exKeyUsg.size() > 0) {
+ for (Iterator exKeyUsgIter = exKeyUsg.iterator(); exKeyUsgIter.hasNext();) {
+ exKeyUsgBfr.append(((String) exKeyUsgIter.next()) + listDelim);
+ }
+
+ X509CertificateAttribute exKeyUsgProp = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_EXKEY_USAGE, (exKeyUsgBfr.toString()).substring(0, exKeyUsgBfr.length() - 2), theCert.getExtendedKeyUsage());
+ elements.add(exKeyUsgProp);
+ }
+
+ } catch (CertificateParsingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+
+ }
+
+ private String getHex(byte buf[]) {
+ String result = ""; //$NON-NLS-1$
+ if (buf != null) {
+ for (int i = 0; i < buf.length; i++) {
+ if (i > 0)
+ result += " "; //$NON-NLS-1$
+
+ short sValue = buf[i];
+ int curInt = 0;
+ curInt += sValue;
+ String converted = Integer.toHexString(curInt);
+
+ if (converted.length() > 2)
+ converted = converted.substring(converted.length() - 2);
+
+ result += converted.toUpperCase();
+ }
+ }
+ return result;
+ }
+
+ private MessageDigest getDigest(String thumAlg) {
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance(thumAlg);
+ } catch (Exception e) {
+ // TODO - Handle the exception or log it..
+ }
+ return md;
+ }
+
+ private String getThumbprint(X509Certificate curCert, String thumAlg) {
+ String thumbPrint = ""; //$NON-NLS-1$
+ try {
+
+ MessageDigest md = getDigest(thumAlg);
+ md.update(curCert.getEncoded());
+ byte rawDigest[] = md.digest();
+ thumbPrint = getHex(rawDigest);
+ } catch (Exception e) {
+ // Might if thumb print algorithm can not be loaded.
+
+ }
+ return thumbPrint;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateAttributeLabelProvider.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateAttributeLabelProvider.java
new file mode 100644
index 0000000..8ebd424
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateAttributeLabelProvider.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2008, Jay Rosenthal
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Jay Rosenthal - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.security.ui;
+
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * X509CertificateAttributeLabelProvider
+ * <p>
+ * Label provider for a 2 column table that shows the attributes (fields) in an X509 digital
+ * certificate.
+ * See <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/security/cert/X509Certificate.html"> X509Certificate </a>
+ * <p>
+ * The first column is the Attribute name and the second column is the string representation of the
+ * attribute's value.
+ * <p>
+ * Used by org.eclipse.equinox.security.ui.wizard.CertificateViewer
+ *
+ */
+public class X509CertificateAttributeLabelProvider extends LabelProvider implements ITableLabelProvider {
+
+ public X509CertificateAttributeLabelProvider() {
+ super();
+
+ }
+
+ public Image getColumnImage(Object element, int columnIndex) {
+
+ return null;
+ }
+
+ public String getColumnText(Object element, int columnIndex) {
+ String text = ""; //$NON-NLS-1$
+
+ if (element instanceof X509CertificateAttribute) {
+ X509CertificateAttribute curEntry = (X509CertificateAttribute) element;
+ switch (columnIndex) {
+ // Attribute/field Name
+ case 0 :
+ text = curEntry.getDescription();
+ break;
+ // Attribute/field string value
+ case 1 :
+ text = curEntry.getStringValue();
+ break;
+ }
+ }
+ return text;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateViewDialog.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateViewDialog.java
new file mode 100644
index 0000000..6883f61
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/X509CertificateViewDialog.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2008, Jay Rosenthal
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Jay Rosenthal - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.equinox.internal.security.ui;
+
+import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import org.eclipse.equinox.internal.security.ui.wizard.CertificateViewer;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+public class X509CertificateViewDialog extends TitleAreaDialog {
+ private final static String titleImageName = "/titleAreaCert.gif"; //$NON-NLS-1$
+ private X509Certificate theCert;
+ private static final DateFormat _df = DateFormat.getDateInstance(DateFormat.LONG);
+ private X500PrincipalHelper nameHelper = new X500PrincipalHelper();
+
+ // We use the "bannerFont" for our bold font
+ private static Font boldFont = JFaceResources.getBannerFont();
+ private Image titleImage;
+
+ public X509CertificateViewDialog(Shell parentShell, X509Certificate cert) {
+ super(parentShell);
+ this.theCert = cert;
+ }
+
+ protected Control createContents(Composite parent) {
+ return super.createContents(parent);
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ nameHelper.setPrincipal(theCert.getSubjectX500Principal());
+
+ setTitle((nameHelper.getCN() != null ? nameHelper.getCN() : nameHelper.getOU()));
+
+ titleImage = Activator.getImageDescriptor(titleImageName).createImage();
+
+ if (titleImage != null)
+ setTitleImage(titleImage);
+
+ Composite composite = (Composite) super.createDialogArea(parent);
+
+ TabFolder tabFolder = new TabFolder(composite, SWT.BORDER);
+ GridData bdata = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL);
+ tabFolder.setLayoutData(bdata);
+
+ createBasicTab(tabFolder);
+
+ createAdvancedTab(tabFolder);
+
+ return composite;
+ }
+
+ private void createBasicTab(TabFolder tabFolder) {
+ String displayName = null;
+ int labelIndent = 10;
+ int dataIdent = 10;
+
+ TabItem basicTab = new TabItem(tabFolder, SWT.NULL);
+ basicTab.setText(SecurityUIMsg.CERTVIEW_LABEL_BASIC);
+ Composite basicTabComposite = new Composite(tabFolder, SWT.NONE);
+
+ GridLayout tabLayout = new GridLayout();
+ tabLayout.numColumns = 2;
+ basicTabComposite.setLayout(tabLayout);
+
+ Label issueToLabel = new Label(basicTabComposite, SWT.NONE);
+ issueToLabel.setText(SecurityUIMsg.CERTPROP_X509_ISSUED_TO);
+ issueToLabel.setFont(boldFont);
+ configureLayout(issueToLabel, 2, 0, 0, 0);
+
+ // Display the RDNs of the Subject
+ nameHelper.setPrincipal(theCert.getSubjectX500Principal());
+
+ Label CNLabel = new Label(basicTabComposite, SWT.NONE);
+ CNLabel.setText(SecurityUIMsg.X500_LABEL_CN);
+ configureLayout(CNLabel, 0, 0, labelIndent, 0);
+
+ Label subjectCN = new Label(basicTabComposite, SWT.NONE);
+ displayName = nameHelper.getCN();
+ subjectCN.setText((displayName != null ? displayName : SecurityUIMsg.CERTVAL_UNDEFINED));
+ configureLayout(subjectCN, 0, 0, dataIdent, 0);
+
+ Label OLabel = new Label(basicTabComposite, SWT.NONE);
+ OLabel.setText(SecurityUIMsg.X500_LABEL_O);
+ configureLayout(OLabel, 0, 0, labelIndent, 0);
+
+ Label subjectO = new Label(basicTabComposite, SWT.NONE);
+ displayName = nameHelper.getO();
+ subjectO.setText((displayName != null ? displayName : SecurityUIMsg.CERTVAL_UNDEFINED));
+ configureLayout(subjectO, 0, 0, dataIdent, 0);
+
+ Label OULabel = new Label(basicTabComposite, SWT.NONE);
+ OULabel.setText(SecurityUIMsg.X500_LABEL_OU);
+ configureLayout(OULabel, 0, 0, labelIndent, 0);
+
+ Label subjectOU = new Label(basicTabComposite, SWT.NONE);
+ displayName = nameHelper.getOU();
+ subjectOU.setText((displayName != null ? displayName : SecurityUIMsg.CERTVAL_UNDEFINED));
+ configureLayout(subjectOU, 0, 0, dataIdent, 0);
+
+ Label issueByLabel = new Label(basicTabComposite, SWT.NONE);
+ issueByLabel.setText(SecurityUIMsg.CERTPROP_X509_ISSUED_BY);
+ configureLayout(issueByLabel, 2, 0, 0, 0);
+ issueByLabel.setFont(boldFont);
+
+ // Display the RDNs of the Issuer
+ nameHelper.setPrincipal(theCert.getIssuerX500Principal());
+
+ Label CNLabel2 = new Label(basicTabComposite, SWT.NONE);
+ CNLabel2.setText(SecurityUIMsg.X500_LABEL_CN);
+ configureLayout(CNLabel2, 0, 0, labelIndent, 0);
+
+ Label issuerCN = new Label(basicTabComposite, SWT.NONE);
+ displayName = nameHelper.getCN();
+ issuerCN.setText((displayName != null ? displayName : SecurityUIMsg.CERTVAL_UNDEFINED));
+ configureLayout(issuerCN, 0, 0, dataIdent, 0);
+
+ Label OLabel2 = new Label(basicTabComposite, SWT.NONE);
+ OLabel2.setText(SecurityUIMsg.X500_LABEL_O);
+ configureLayout(OLabel2, 0, 0, labelIndent, 0);
+
+ Label issuerO = new Label(basicTabComposite, SWT.NONE);
+ displayName = nameHelper.getO();
+ issuerO.setText((displayName != null ? displayName : SecurityUIMsg.CERTVAL_UNDEFINED));
+ configureLayout(issuerO, 0, 0, dataIdent, 0);
+
+ Label OULabel2 = new Label(basicTabComposite, SWT.NONE);
+ OULabel2.setText(SecurityUIMsg.X500_LABEL_OU);
+ configureLayout(OULabel2, 0, 0, labelIndent, 0);
+
+ Label issuerOU = new Label(basicTabComposite, SWT.NONE);
+ displayName = nameHelper.getOU();
+ issuerOU.setText((displayName != null ? displayName : SecurityUIMsg.CERTVAL_UNDEFINED));
+ configureLayout(issuerOU, 0, 0, dataIdent, 0);
+
+ Label datesLabel = new Label(basicTabComposite, SWT.NONE);
+ datesLabel.setText(SecurityUIMsg.CERTVIEW_LABEL_VALIDITY_DATES);
+ configureLayout(datesLabel, 2, 0, 0, 0);
+ datesLabel.setFont(boldFont);
+
+ Label validFrom = new Label(basicTabComposite, SWT.NONE);
+ validFrom.setText(SecurityUIMsg.CERTPROP_X509_VALID_FROM);
+ configureLayout(validFrom, 0, 0, labelIndent, 0);
+
+ Label fromDate = new Label(basicTabComposite, SWT.NONE);
+ fromDate.setText(_df.format(theCert.getNotBefore()));
+ configureLayout(fromDate, 0, 0, dataIdent, 0);
+
+ Label validTo = new Label(basicTabComposite, SWT.NONE);
+ validTo.setText(SecurityUIMsg.CERTPROP_X509_VALID_TO);
+ configureLayout(validTo, 0, 0, labelIndent, 0);
+
+ Label toDate = new Label(basicTabComposite, SWT.NONE);
+ toDate.setText(_df.format(theCert.getNotAfter()));
+ configureLayout(toDate, 0, 0, dataIdent, 0);
+
+ basicTab.setControl(basicTabComposite);
+ }
+
+ protected static void configureLayout(Control c, int horizontalSpan, int verticalSpan, int horizontalIndent, int vertIndent) {
+ GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_CENTER);
+
+ gd.horizontalSpan = horizontalSpan;
+ gd.verticalSpan = verticalSpan;
+ gd.horizontalIndent = horizontalIndent;
+ gd.verticalIndent = vertIndent;
+
+ c.setLayoutData(gd);
+
+ }
+
+ private void createAdvancedTab(final TabFolder tabFolder) {
+ TabItem advancedTab = new TabItem(tabFolder, SWT.NULL);
+ advancedTab.setText(SecurityUIMsg.CERTVIEW_LABEL_DETAILS);
+ Composite advTabComposite = new Composite(tabFolder, SWT.NONE);
+ advTabComposite.setLayout(new FillLayout(SWT.VERTICAL));
+
+ CertificateViewer certViewer = new CertificateViewer(advTabComposite);
+ certViewer.setCertificate(theCert);
+ advancedTab.setControl(advTabComposite);
+ }
+
+ protected void setShellStyle(int newShellStyle) {
+
+ super.setShellStyle(newShellStyle | SWT.RESIZE | SWT.DIALOG_TRIM);
+ }
+
+ protected void createButtonsForButtonBar(Composite parent) {
+ // The default has only a "Close" button, but it returns the CANCEL Id
+ createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CLOSE_LABEL, true);
+
+ }
+
+ public boolean close() {
+ if (titleImage != null) {
+ titleImage.dispose();
+ }
+ return super.close();
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/nls/SecUIMessages.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/nls/SecUIMessages.java
new file mode 100644
index 0000000..a61f00c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/nls/SecUIMessages.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.nls;
+
+import org.eclipse.osgi.util.NLS;
+
+public class SecUIMessages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.equinox.internal.security.ui.nls.messages"; //$NON-NLS-1$
+
+ public static String enterPasswordLabel;
+ public static String enterKeystorePassword;
+ public static String callbackhandlerUnavailable;
+ public static String passwordLabel;
+ public static String passwordRequired;
+ public static String noDigestAlgorithm;
+
+ // login dialog
+ public static String buttonLogin;
+ public static String buttonExit;
+ public static String messageLogin;
+ public static String messageEmptyPassword;
+ public static String messageNoMatch;
+ public static String labelPassword;
+ public static String labelConfirm;
+ public static String dialogTitle;
+ public static String showPassword;
+ public static String noDigestPassword;
+
+ // exception handling
+ public static String exceptionOccured;
+ public static String exceptionTitle;
+ public static String exceptionDecode;
+
+ static {
+ // load message values from bundle file
+ reloadMessages();
+ }
+
+ public static void reloadMessages() {
+ NLS.initializeMessages(BUNDLE_NAME, SecUIMessages.class);
+ }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/nls/messages.properties b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/nls/messages.properties
new file mode 100644
index 0000000..0468777
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/nls/messages.properties
@@ -0,0 +1,35 @@
+###############################################################################
+# Copyright (c) 2005, 2008 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+
+## General use
+enterPasswordLabel = Enter password:
+enterKeystorePassword = Enter the password to unlock your platform KeyStore.
+callbackhandlerUnavailable = CallbackHandler is required but not available.
+passwordRequired = Password is required.
+noDigestAlgorithm = SHA-1 Digest not available. Check the Java configuration file java.security.
+passwordLabel = Password:
+
+## Login dialog
+messageLogin = Please enter the secure storage password
+messageEmptyPassword = Password can not be empty
+messageNoMatch = Password and confirmation characters did not match
+labelPassword = &Password:
+labelConfirm = &Confirm password:
+buttonLogin = Login
+buttonExit = Exit
+dialogTitle = Secure storage login
+showPassword = &Show password
+noDigestPassword = The message digest algorithm \"{0}\" is not available.
+
+## exception handling
+exceptionOccured = {0} See log for details.
+exceptionTitle = Secure storage
+exceptionDecode = Incorrect password or data is corrupted. Would you like to re-log?
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/AdvancedPage.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/AdvancedPage.java
new file mode 100644
index 0000000..bd868be
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/AdvancedPage.java
@@ -0,0 +1,495 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.preferences;
+
+import java.lang.reflect.Constructor;
+import java.security.*;
+import java.util.*;
+import java.util.List;
+import org.eclipse.equinox.internal.security.ui.SecurityUIMsg;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.viewers.*;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.osgi.framework.Bundle;
+
+public class AdvancedPage extends PreferencePage implements IWorkbenchPreferencePage {
+
+ private static final String ALG_ALIAS = "Alg.Alias."; //$NON-NLS-1$
+ private static final String PROVIDER = "Provider."; //$NON-NLS-1$
+
+ TreeViewer providerViewer;
+ Combo providerCombo;
+ Label versionText;
+ Label descriptionText;
+
+ public AdvancedPage() {
+ //empty
+ }
+
+ public void init(IWorkbench workbench) {
+ this.noDefaultAndApplyButton();
+ }
+
+ protected Control createContents(Composite parent) {
+
+ Composite area = new Composite(parent, SWT.NONE);
+ area.setLayout(new FormLayout());
+
+ Label providerLabel = new Label(area, SWT.NONE);
+ providerLabel.setText(SecurityUIMsg.ADVPAGE_LABEL_PROVIDER);
+ FormData data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ providerLabel.setData(data);
+
+ providerCombo = new Combo(area, SWT.DROP_DOWN | SWT.READ_ONLY);
+ data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ data.left = new FormAttachment(providerLabel, 0);
+ //data.right = new FormAttachment(100, 0);
+ //data.height = 5 * providerCombo.getItemHeight();
+ data.width = 100;
+ providerCombo.setLayoutData(data);
+
+ Provider[] providers = Security.getProviders();
+ for (int i = 0; i < providers.length; i++) {
+ providerCombo.add(i + ": " + providers[i].getName()); //$NON-NLS-1$
+ }
+ providerCombo.setVisibleItemCount(providers.length);
+ providerCombo.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event event) {
+ Provider provider = Security.getProviders()[providerCombo.getSelectionIndex()];
+ providerViewer.setInput(getContent(provider));
+ versionText.setText(String.valueOf(provider.getVersion()));
+ descriptionText.setText(provider.getInfo());
+ }
+ });
+
+ Link link = new Link(area, SWT.NONE);
+ link.setText(SecurityUIMsg.ADVPAGE_LABEL_LINK);
+ link.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event event) {
+ //todo
+ }
+ });
+
+ data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ data.right = new FormAttachment(100, 0);
+ link.setLayoutData(data);
+
+ Label versionLabel = new Label(area, SWT.NONE);
+ versionLabel.setText(SecurityUIMsg.ADVPAGE_LABEL_VERSION);
+ data = new FormData();
+ data.top = new FormAttachment(providerCombo, 0);
+ data.left = new FormAttachment(0, 0);
+ versionLabel.setLayoutData(data);
+
+ versionText = new Label(area, SWT.NONE);
+ data = new FormData();
+ data.top = new FormAttachment(providerCombo, 0);
+ data.left = new FormAttachment(versionLabel, 0);
+ data.right = new FormAttachment(100, 0);
+ versionText.setLayoutData(data);
+
+ Label descriptionLabel = new Label(area, SWT.NONE);
+ descriptionLabel.setText(SecurityUIMsg.ADVPAGE_LABEL_DESCRIPTION);
+ data = new FormData();
+ data.top = new FormAttachment(versionLabel, 0);
+ data.left = new FormAttachment(0, 0);
+ descriptionLabel.setLayoutData(data);
+
+ descriptionText = new Label(area, SWT.NONE);
+ data = new FormData();
+ data.top = new FormAttachment(versionText, 0);
+ data.left = new FormAttachment(versionLabel, 0);
+ data.right = new FormAttachment(100, 0);
+ data.width = 250;
+ descriptionText.setLayoutData(data);
+
+ Group serviceGroup = new Group(area, SWT.NONE);
+ serviceGroup.setText(SecurityUIMsg.ADVPAGE_LABEL_SERVICES);
+ data = new FormData();
+ data.top = new FormAttachment(descriptionLabel, 0);
+ data.bottom = new FormAttachment(100, 0);
+ data.left = new FormAttachment(0, 0);
+ data.right = new FormAttachment(100, 0);
+ serviceGroup.setLayoutData(data);
+
+ serviceGroup.setLayout(new FormLayout());
+
+ providerViewer = new TreeViewer(serviceGroup);
+ providerViewer.setContentProvider(new ProviderContentProvider());
+ providerViewer.setLabelProvider(new ProviderLabelProvider());
+ Tree tree = (Tree) providerViewer.getControl();
+
+ data = new FormData();
+ data.top = new FormAttachment(0, 5);
+ data.left = new FormAttachment(0, 5);
+ data.right = new FormAttachment(100, -5);
+ data.bottom = new FormAttachment(100, -5);
+ data.height = (10 * tree.getItemHeight()) + tree.getHeaderHeight();
+ providerViewer.getControl().setLayoutData(data);
+
+ providerCombo.select(0);
+ Provider provider = Security.getProviders()[0];
+ providerViewer.setInput(getContent(provider));
+ versionText.setText(String.valueOf(provider.getVersion()));
+ descriptionText.setText(provider.getInfo());
+
+ return area;
+ }
+
+ Object[] getContent(Provider provider) {
+
+ Set providerKeys = provider.keySet();
+ Hashtable serviceList = new Hashtable();
+ Hashtable attributeMap = new Hashtable(); // "type" => "Hashtable of (attribute,value) pairs"
+ Hashtable aliasMap = new Hashtable(); // "type" => "Arraylist of aliases"
+ for (Iterator it = providerKeys.iterator(); it.hasNext();) {
+ String key = (String) it.next();
+
+ // this is provider info, available off the Provider API
+ if (key.startsWith(PROVIDER)) {
+ continue;
+ }
+
+ // this is an alias
+ if (key.startsWith(ALG_ALIAS)) {
+ String value = key.substring(key.indexOf(ALG_ALIAS) + ALG_ALIAS.length(), key.length());
+ String type = (String) provider.get(key);
+ String algo = value.substring(0, value.indexOf('.'));
+ String alias = value.substring(value.indexOf('.') + 1, value.length());
+ ArrayList aliasList = (ArrayList) aliasMap.get(type + '.' + algo);
+ if (aliasList == null) {
+ aliasList = new ArrayList();
+ aliasList.add(alias);
+ aliasMap.put(type, aliasList);
+ } else {
+ aliasList.add(alias);
+ }
+ }
+
+ // this is an attribute
+ else if (key.indexOf(' ') > -1) {
+ String type = key.substring(0, key.indexOf('.'));
+ String algorithm = key.substring(key.indexOf('.') + 1, key.indexOf(' '));
+ String attribute = key.substring(key.indexOf(' ') + 1, key.length());
+ String value = (String) provider.get(key);
+ Hashtable attributeTable = (Hashtable) attributeMap.get(type + '.' + algorithm);
+ if (attributeTable == null) {
+ attributeTable = new Hashtable();
+ attributeTable.put(attribute, value);
+ attributeMap.put(type + '.' + algorithm, attributeTable);
+ } else {
+ attributeTable.put(attribute, value);
+ }
+ }
+
+ // else this is a service
+ else {
+ serviceList.put(key, provider.get(key));
+ }
+ }
+
+ ProviderService[] serviceArray = new ProviderService[serviceList.size()];
+ Set serviceKeys = serviceList.keySet();
+ int serviceCount = 0;
+ for (Iterator it = serviceKeys.iterator(); it.hasNext();) {
+ String key = (String) it.next();
+ String type = key.substring(0, key.indexOf('.'));
+ String algo = key.substring(key.indexOf('.') + 1, key.length());
+ String className = (String) serviceList.get(key);
+ List aliases = (List) aliasMap.get(algo);
+ Map attributes = (Map) attributeMap.get(key);
+
+ serviceArray[serviceCount] = new ProviderService(type, algo, className, aliases, attributes, null);
+ serviceCount++;
+ }
+
+ // sort the provider services
+ Arrays.sort(serviceArray, new Comparator() {
+ public int compare(Object arg0, Object arg1) {
+ ProviderService s0 = (ProviderService) arg0;
+ ProviderService s1 = (ProviderService) arg1;
+ return s0.getType().compareTo(s1.getType());
+ }
+ });
+
+ return serviceArray;
+ }
+
+ class ProviderContentProvider implements ITreeContentProvider {
+
+ public Object[] getElements(Object inputElement) {
+ Object[] returnValue = null;
+ if (inputElement instanceof ProviderService[]) {
+ returnValue = (Object[]) inputElement;
+ }
+ return returnValue;
+ }
+
+ public Object getParent(Object element) {
+ Object returnValue = null;
+ if (element instanceof ProviderServiceDetail) {
+ returnValue = ((ProviderServiceDetail) element).getParent();
+ }
+ return returnValue;
+ }
+
+ public Object[] getChildren(Object parentElement) {
+ Object[] returnValue = null;
+ if (parentElement instanceof ProviderService) {
+ ProviderService service = (ProviderService) parentElement;
+ ArrayList detailList = new ArrayList();
+ detailList.add(new ProviderServiceDetail(service, TYPE_CLASSNAME, service.getClassName()));
+ if (service.getAliases() != null) {
+ detailList.add(new ProviderServiceDetail(service, TYPE_ALIASES, service.getAliases()));
+ }
+ if (service.getAttributes() != null) {
+ detailList.add(new ProviderServiceDetail(service, TYPE_ATTRIBUTES, service.getAttributes()));
+ }
+ returnValue = detailList.toArray(new ProviderServiceDetail[] {});
+ } else if (parentElement instanceof ProviderServiceDetail) {
+ returnValue = ((ProviderServiceDetail) parentElement).getChildren();
+ }
+ return returnValue;
+ }
+
+ public boolean hasChildren(Object element) {
+ boolean returnValue = false;
+ if (element instanceof ProviderService) {
+ returnValue = true;
+ } else if (element instanceof ProviderServiceDetail) {
+ returnValue = ((ProviderServiceDetail) element).hasChildren();
+ }
+ return returnValue;
+ }
+
+ public void dispose() {
+ //nothing to do
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ //empty
+ }
+ }
+
+ class ProviderLabelProvider implements ILabelProvider {
+
+ public Image getImage(Object element) {
+ return null;
+ }
+
+ public String getText(Object element) {
+ String returnValue = null;
+ if (element instanceof String) {
+ returnValue = (String) element;
+ } else if (element instanceof ProviderService) {
+ ProviderService service = (ProviderService) element;
+ returnValue = service.getType() + ": " + service.getAlgorithm(); //$NON-NLS-1$
+ } else if (element instanceof ProviderServiceDetail) {
+ ProviderServiceDetail detail = (ProviderServiceDetail) element;
+ returnValue = detail.toString();
+ } else if (element instanceof ProviderServiceAttribute) {
+ ProviderServiceAttribute attribute = (ProviderServiceAttribute) element;
+ returnValue = attribute.toString();
+ }
+ return returnValue;
+ }
+
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ public void addListener(ILabelProviderListener listener) {
+ //empty
+ }
+
+ public void removeListener(ILabelProviderListener listener) {
+ //empty
+ }
+
+ public void dispose() {
+ //empty
+ }
+ }
+
+ private class ProviderService {
+ private final String type;
+ private final String algorithm;
+ private final String className;
+ private final List aliases;
+ private final Map attributes;
+ private final Bundle providingBundle;
+
+ public ProviderService(String type, String algorithm, String className, List aliases, Map attributes, Bundle providingBundle) {
+ this.type = type;
+ this.algorithm = algorithm;
+ this.className = className;
+ this.aliases = aliases;
+ this.attributes = attributes;
+ this.providingBundle = providingBundle;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public List getAliases() {
+ return aliases;
+ }
+
+ public Map getAttributes() {
+ return attributes;
+ }
+
+ public Object newInstance(Object parameter) throws NoSuchAlgorithmException {
+ Object obj = null;
+ try {
+ Class clazz = providingBundle.loadClass(getClassName());
+ if (parameter != null) {
+ try {
+ Constructor cons = clazz.getDeclaredConstructor(new Class[] {parameter.getClass()});
+ obj = cons.newInstance(new Object[] {parameter});
+ } catch (NoSuchMethodException e) {
+ throw new InvalidParameterException();
+ }
+ } else {
+ obj = clazz.newInstance();
+ }
+ } catch (Throwable t) {
+ throw new NoSuchAlgorithmException();
+ }
+
+ return obj;
+ }
+
+ public boolean supportsParameter(Object parameter) {
+ try {
+ Class clazz = providingBundle.loadClass(getClassName());
+ clazz.getDeclaredConstructor(new Class[] {parameter.getClass()});
+ } catch (Throwable t) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ // private static final int TYPE_ALGORITHM = 0;
+ // private static final int TYPE_TYPE = 1;
+ // private static final int TYPE_BUNDLEID = 2;
+ private static final int TYPE_CLASSNAME = 3;
+ private static final int TYPE_ALIASES = 4;
+ private static final int TYPE_ATTRIBUTES = 5;
+
+ private class ProviderServiceDetail {
+
+ ProviderService parent;
+ int type;
+ Object data;
+
+ ProviderServiceDetail(ProviderService parent, int type, Object data) {
+ this.parent = parent;
+ this.type = type;
+ this.data = data;
+ }
+
+ int getType() {
+ return type;
+ }
+
+ Object getData() {
+ return data;
+ }
+
+ ProviderService getParent() {
+ return parent;
+ }
+
+ public String toString() {
+ String returnValue = null;
+ switch (getType()) {
+ case TYPE_CLASSNAME :
+ returnValue = SecurityUIMsg.ADVPAGE_LABEL_CLASS + (String) getData();
+ break;
+
+ case TYPE_ALIASES :
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(SecurityUIMsg.ADVPAGE_LABEL_ALIASES);
+ String[] aliases = (String[]) ((List) getData()).toArray(new String[] {});
+ for (int i = 0; i < aliases.length; i++) {
+ buffer.append(aliases[i]);
+ if (i < aliases.length - 1) {
+ buffer.append(", "); //$NON-NLS-1$
+ }
+ }
+ returnValue = buffer.toString();
+ break;
+
+ case TYPE_ATTRIBUTES :
+ returnValue = SecurityUIMsg.ADVPAGE_LABEL_ATTRIBUTES;
+ break;
+ }
+ return returnValue;
+ }
+
+ boolean hasChildren() {
+ boolean returnValue = false;
+ if (getType() == TYPE_ATTRIBUTES) {
+ returnValue = true;
+ }
+ return returnValue;
+ }
+
+ Object[] getChildren() {
+ Object[] returnValue = null;
+ if (getType() == TYPE_ATTRIBUTES) {
+ Map attributeMap = (Map) getData();
+ ArrayList attributeList = new ArrayList();
+ for (Iterator it = attributeMap.keySet().iterator(); it.hasNext();) {
+ String key = (String) it.next();
+ String value = (String) attributeMap.get(key);
+ attributeList.add(new ProviderServiceAttribute(key, value));
+ }
+ returnValue = attributeList.toArray(new ProviderServiceAttribute[] {});
+ }
+ return returnValue;
+ }
+ }
+
+ private class ProviderServiceAttribute {
+
+ String key;
+ String value;
+
+ public ProviderServiceAttribute(String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public String toString() {
+ return key + ": " + value; //$NON-NLS-1$
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/CertificatesPage.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/CertificatesPage.java
new file mode 100644
index 0000000..5928041
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/CertificatesPage.java
@@ -0,0 +1,435 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.preferences;
+
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.*;
+import org.eclipse.equinox.internal.security.ui.*;
+import org.eclipse.equinox.internal.security.ui.wizard.CertificateImportWizard;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.viewers.*;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.osgi.service.security.TrustEngine;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+//potential enhancements
+//
+public class CertificatesPage extends PreferencePage implements IWorkbenchPreferencePage {
+
+ private static final int VIEW_ISSUE_TO_COLUMN_INDEX = 0;
+ private static final int VIEW_ISSUE_BY_COLUMN_INDEX = 1;
+ private static final int VIEW_PROVIDER_COLUMN_INDEX = 2;
+
+ TrustEngine[] activeTrustEngines;
+ TableViewer tableViewer;
+ Table tableCert;
+ CertRowEntry currentSelection;
+ Button removeBtn;
+ Button viewButton;
+
+ private class CertTableSorter implements Listener {
+
+ final int columnSelected;
+ private final CertRowEntry[] certRowEntry;
+
+ CertTableSorter(final int columnSelected, final CertRowEntry[] certRowEntry) {
+ this.columnSelected = columnSelected;
+ this.certRowEntry = certRowEntry;
+ }
+
+ public void handleEvent(Event e) {
+
+ // get the sort column and figure out the direction
+ TableColumn sortColumn = tableCert.getSortColumn();
+ TableColumn currentColumn = (TableColumn) e.widget;
+ int dir = tableCert.getSortDirection();
+
+ if (sortColumn == currentColumn) {
+ dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+ } else {
+ tableCert.setSortColumn(currentColumn);
+ dir = SWT.UP;
+ }
+
+ final int direction = dir;
+ Arrays.sort(certRowEntry, new Comparator() {
+ public int compare(Object arg0, Object arg1) {
+
+ if (columnSelected == VIEW_ISSUE_TO_COLUMN_INDEX) {
+ String issueTo1 = getSubjectCommonName(((CertRowEntry) arg0).cert);
+ String issueTo2 = getSubjectCommonName(((CertRowEntry) arg1).cert);
+ if (direction == SWT.UP)
+ return issueTo1.compareTo(issueTo2);
+ return issueTo2.compareTo(issueTo1);
+
+ } else if (columnSelected == VIEW_ISSUE_BY_COLUMN_INDEX) {
+ String issueOrg1 = getIssuerOrg(((CertRowEntry) arg0).cert);
+ String issueOrg2 = getIssuerOrg(((CertRowEntry) arg1).cert);
+ if (direction == SWT.UP)
+ return issueOrg1.compareTo(issueOrg2);
+ return issueOrg2.compareTo(issueOrg1);
+ } else {
+ String provider1 = activeTrustEngines[((CertRowEntry) arg0).trustEngineIndex].getName();
+ String provider2 = activeTrustEngines[((CertRowEntry) arg1).trustEngineIndex].getName();
+ if (direction == SWT.UP)
+ return provider1.compareTo(provider2);
+ return provider2.compareTo(provider1);
+ }
+ }
+ });
+ // update data displayed in table
+ tableCert.setSortDirection(dir);
+ tableCert.clearAll();
+ tableViewer.setInput(certRowEntry);
+ }
+ }
+
+ public CertificatesPage() {
+ //empty
+ }
+
+ public void init(IWorkbench workbench) {
+ this.noDefaultAndApplyButton();
+ }
+
+ protected Control createContents(Composite parent) {
+ initTrustEngines();
+
+ Composite page = new Composite(parent, SWT.NONE);
+ FormLayout layout = new FormLayout();
+ page.setLayout(layout);
+
+ Label titleLabel = new Label(page, SWT.NONE);
+ titleLabel.setText(SecurityUIMsg.CERTPAGE_LABEL_TITLE);
+
+ FormData data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ //data.bottom = new FormAttachment(100, 0);
+ data.left = new FormAttachment(0, 0);
+ //data.right = new FormAttachment(100, 0);
+ //data.width = 100;
+ titleLabel.setLayoutData(data);
+
+ Link link = new Link(page, SWT.NONE);
+ link.setText(SecurityUIMsg.CERTPAGE_LABEL_LINK);
+ link.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event event) {
+ //todo
+ }
+ });
+
+ data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ //data.bottom = new FormAttachment(100, 0);
+ //data.left = new FormAttachment(tableArea, 0);
+ data.right = new FormAttachment(100, 0);
+ //data.width = 100;
+ link.setLayoutData(data);
+
+ Label tableLabel = new Label(page, SWT.NONE);
+ tableLabel.setText(SecurityUIMsg.CERTPAGE_TABLE_LABEL);
+
+ data = new FormData();
+ data.top = new FormAttachment(titleLabel, 10);
+ //data.bottom = new FormAttachment(100, 0);
+ data.left = new FormAttachment(0, 0);
+ //data.right = new FormAttachment(100, 0);
+ //data.width = 100;
+ tableLabel.setLayoutData(data);
+
+ Composite tableArea = new Composite(page, SWT.NONE);
+ FormLayout tableLayout = new FormLayout();
+ tableArea.setLayout(tableLayout);
+
+ Composite buttonArea = new Composite(page, SWT.NONE);
+ FormLayout buttonLayout = new FormLayout();
+ buttonArea.setLayout(buttonLayout);
+
+ data = new FormData();
+ data.top = new FormAttachment(tableLabel, 5);
+ data.bottom = new FormAttachment(100, 0);
+ //data.left = new FormAttachment(tableArea, 0);
+ data.right = new FormAttachment(100, 0);
+ //data.width = 100;
+ buttonArea.setLayoutData(data);
+
+ data = new FormData();
+ data.top = new FormAttachment(tableLabel, 5);
+ data.bottom = new FormAttachment(100, 0);
+ data.left = new FormAttachment(0, 0);
+ data.right = new FormAttachment(buttonArea, 0);
+ tableArea.setLayoutData(data);
+
+ tableViewer = new TableViewer(tableArea, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION);
+ tableCert = (Table) tableViewer.getControl();
+ tableCert.setHeaderVisible(true);
+ data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ data.bottom = new FormAttachment(100, 0);
+ data.left = new FormAttachment(0, 0);
+ data.right = new FormAttachment(100, 0);
+ data.height = (10 * tableCert.getItemHeight());
+ tableCert.setLayoutData(data);
+
+ TableColumn column1 = new TableColumn(tableCert, SWT.NULL);
+ column1.setText(SecurityUIMsg.CERTPAGE_TABLE_HEADER_ISSUEDTO);
+ column1.setWidth(200);
+ column1.addListener(SWT.Selection, new CertTableSorter(VIEW_ISSUE_TO_COLUMN_INDEX, getCertificates()));
+
+ TableColumn column2 = new TableColumn(tableCert, SWT.NULL);
+ column2.setText(SecurityUIMsg.CERTPAGE_TABLE_HEADER_ISSUEDBY);
+ column2.setWidth(200);
+ column2.addListener(SWT.Selection, new CertTableSorter(VIEW_ISSUE_BY_COLUMN_INDEX, getCertificates()));
+
+ TableColumn column3 = new TableColumn(tableCert, SWT.NULL);
+ column3.setText(SecurityUIMsg.CERTPAGE_TABLE_HEADER_PROVIDER);
+ column3.setWidth(200);
+ column3.addListener(SWT.Selection, new CertTableSorter(VIEW_PROVIDER_COLUMN_INDEX, getCertificates()));
+
+ Button button1 = new Button(buttonArea, SWT.PUSH);
+ button1.setText(SecurityUIMsg.CERTPAGE_BUTTON_IMPORT);
+ button1.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ //do nothing
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ openImportWizard();
+ }
+
+ });
+
+ data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ //data.bottom = new FormAttachment(100, 0);
+ data.left = new FormAttachment(0, 5);
+ data.right = new FormAttachment(100, 0);
+ data.width = 100;
+ data.height = 25;
+ button1.setLayoutData(data);
+
+ Button button2 = new Button(buttonArea, SWT.PUSH);
+ button2.setText(SecurityUIMsg.CERTPAGE_BUTTON_EXPORT);
+ data = new FormData();
+ data.top = new FormAttachment(button1, 5);
+ //data.bottom = new FormAttachment(100, 0);null
+ data.left = new FormAttachment(0, 5);
+ //data.right = new FormAttachment(100, 0);
+ data.width = 100;
+ data.height = 25;
+ button2.setLayoutData(data);
+
+ viewButton = new Button(buttonArea, SWT.PUSH);
+ viewButton.setText(SecurityUIMsg.CERTPAGE_BUTTON_VIEW);
+ viewButton.setEnabled(false);
+ data = new FormData();
+ data.top = new FormAttachment(button2, 5);
+ //data.bottom = new FormAttachment(100, 0);null
+ data.left = new FormAttachment(0, 5);
+ //data.right = new FormAttachment(100, 0);
+ data.width = 100;
+ data.height = 25;
+ viewButton.setLayoutData(data);
+
+ viewButton.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // TODO Auto-generated method stub
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ X509CertificateViewDialog certViewer = new X509CertificateViewDialog(tableViewer.getTable().getShell(), (X509Certificate) currentSelection.cert);
+ certViewer.open();
+ }
+ });
+
+ removeBtn = new Button(buttonArea, SWT.PUSH);
+ removeBtn.setEnabled(false);
+ removeBtn.setText(SecurityUIMsg.CERTPAGE_BUTTON_REMOVE);
+ data = new FormData();
+ data.top = new FormAttachment(viewButton, 5);
+ //data.bottom = new FormAttachment(100, 0);
+ data.left = new FormAttachment(0, 5);
+ data.right = new FormAttachment(100, 0);
+ data.width = 100;
+ data.height = 25;
+ removeBtn.setLayoutData(data);
+ removeBtn.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // TODO Auto-generated method stub
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ removeSelected();
+ }
+ });
+
+ initTrustEngines();
+ tableViewer.setContentProvider(new SystemCertificatesContentProvider());
+ tableViewer.setLabelProvider(new SystemCertificatesLabelProvider(activeTrustEngines));
+ tableViewer.setInput(getCertificates());
+ tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ if (event.getSelection() instanceof IStructuredSelection) {
+ viewButton.setEnabled(true);
+ currentSelection = (CertRowEntry) ((IStructuredSelection) event.getSelection()).getFirstElement();
+ if (null != currentSelection && !activeTrustEngines[currentSelection.trustEngineIndex].isReadOnly()) {
+ removeBtn.setEnabled(true);
+
+ }
+ }
+
+ }
+ });
+
+ return page;
+ }
+
+ protected void openImportWizard() {
+ CertificateImportWizard wizard = new CertificateImportWizard();
+ WizardDialog dialog = new WizardDialog(getShell(), wizard);
+ dialog.create();
+ if (dialog.open() == 0) {
+ // reload the table viewer
+ tableViewer.setInput(getCertificates());
+ }
+ }
+
+ void removeSelected() {
+ try {
+ // get the confirmation first
+ ConfirmationDialog confirmationDilaog = new ConfirmationDialog(tableViewer.getTable().getShell(), currentSelection.cert);
+ if (confirmationDilaog.open() == ConfirmationDialog.YES) {
+ activeTrustEngines[currentSelection.trustEngineIndex].removeTrustAnchor(currentSelection.cert);
+ tableViewer.setInput(getCertificates());
+ removeBtn.setEnabled(false);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private CertRowEntry[] getCertificates() {
+ ArrayList certs = new ArrayList();
+ try {
+ for (int i = 0; i < activeTrustEngines.length; i++) {
+ String[] aliases = activeTrustEngines[i].getAliases();
+ for (int j = 0; j < aliases.length; j++) {
+ CertRowEntry certRowEntry = new CertRowEntry(activeTrustEngines[i].getTrustAnchor(aliases[j]), i);
+ certs.add(certRowEntry);
+ }
+ }
+ return (CertRowEntry[]) certs.toArray(new CertRowEntry[] {});
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private void initTrustEngines() {
+ if (activeTrustEngines == null) {
+ activeTrustEngines = Activator.getTrustEngines();
+ }
+ }
+
+ private class CertRowEntry {
+ public Certificate cert;
+ public int trustEngineIndex;
+
+ public CertRowEntry(Certificate cert, int trustIndex) {
+ this.cert = cert;
+ this.trustEngineIndex = trustIndex;
+ }
+ }
+
+ class SystemCertificatesContentProvider implements IStructuredContentProvider {
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // TODO Auto-generated method stub
+ }
+
+ public Object[] getElements(Object inputElement) {
+
+ if (inputElement instanceof CertRowEntry[]) {
+ return (Object[]) inputElement;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public void dispose() {
+ //nothing to dispose
+ }
+ }
+
+ class SystemCertificatesLabelProvider extends LabelProvider implements ITableLabelProvider {
+
+ private TrustEngine[] tEngines;
+
+ public SystemCertificatesLabelProvider(TrustEngine[] engines) {
+ this.tEngines = engines;
+ }
+
+ public Image getColumnImage(Object element, int columnIndex) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getColumnText(Object element, int columnIndex) {
+ String label = null;
+ CertRowEntry certRowEntry = (CertRowEntry) element;
+ switch (columnIndex) {
+ case 0 :
+ label = getSubjectCommonName(certRowEntry.cert);
+ break;
+
+ case 1 :
+ label = getIssuerOrg(certRowEntry.cert);
+ break;
+
+ case 2 :
+ label = tEngines[certRowEntry.trustEngineIndex].getName();
+ break;
+
+ default :
+ break;
+ }
+ return label;
+ }
+ }
+
+ static String getSubjectCommonName(Certificate cert) {
+ if (cert instanceof X509Certificate) {
+ X500PrincipalHelper cnHelper = new X500PrincipalHelper(((X509Certificate) cert).getSubjectX500Principal());
+ //If there isn't a CN attribute, return the OU instead
+ return (cnHelper.getCN() != null ? cnHelper.getCN() : cnHelper.getOU());
+ }
+ return SecurityUIMsg.CERTPAGE_ERROR_UNKNOWN_FORMAT;
+ }
+
+ static String getIssuerOrg(Certificate cert) {
+ if (cert instanceof X509Certificate) {
+ X500PrincipalHelper cnHelper = new X500PrincipalHelper(((X509Certificate) cert).getIssuerX500Principal());
+ String retOrg = (cnHelper.getO() != null ? cnHelper.getO() : cnHelper.getOU());
+ return retOrg;
+ }
+ return SecurityUIMsg.CERTPAGE_ERROR_UNKNOWN_FORMAT;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/PolicyPage.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/PolicyPage.java
new file mode 100644
index 0000000..7f8aa47
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/PolicyPage.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.preferences;
+
+import org.eclipse.equinox.internal.security.ui.SecurityUIMsg;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+public class PolicyPage extends PreferencePage implements IWorkbenchPreferencePage {
+
+ Button anyButton;
+ Button anysignedButton;
+ Button onlytrustedButton;
+ Button expiredButton;
+
+ protected Control createContents(Composite parent) {
+
+ Composite page = new Composite(parent, SWT.NONE);
+ page.setLayout(new FormLayout());
+
+ Label titleLabel = new Label(page, SWT.NONE);
+ titleLabel.setText(SecurityUIMsg.POLPAGE_LABEL_TITLE);
+ FormData data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ data.left = new FormAttachment(0, 0);
+ titleLabel.setLayoutData(data);
+
+ TabFolder folder = new TabFolder(page, SWT.NONE);
+ folder.setLayout(new FormLayout());
+ data = new FormData();
+ data.top = new FormAttachment(titleLabel, 10);
+ data.left = new FormAttachment(0, 0);
+ data.right = new FormAttachment(100, 0);
+ data.bottom = new FormAttachment(100, 0);
+ folder.setLayoutData(data);
+
+ TabItem item = new TabItem(folder, SWT.NONE);
+ item.setText(SecurityUIMsg.POLPAGE_LABEL_SECTION);
+
+ Composite loadArea = new Composite(folder, SWT.NONE);
+ loadArea.setLayout(new FormLayout());
+
+ item.setControl(loadArea);
+
+ data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ data.left = new FormAttachment(0, 0);
+ data.right = new FormAttachment(100, 0);
+ data.bottom = new FormAttachment(100, 0);
+ loadArea.setLayoutData(data);
+
+ anyButton = new Button(loadArea, SWT.RADIO);
+ anysignedButton = new Button(loadArea, SWT.RADIO);
+ onlytrustedButton = new Button(loadArea, SWT.RADIO);
+ expiredButton = new Button(loadArea, SWT.CHECK);
+
+ anyButton.setText(SecurityUIMsg.POLPAGE_BUTTON_ALLOW_ANY);
+ anyButton.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent event) {
+ //do nothing
+ }
+
+ public void widgetSelected(SelectionEvent event) {
+ expiredButton.setEnabled(false);
+ }
+ });
+ data = new FormData();
+ data.top = new FormAttachment(0, 5);
+ data.left = new FormAttachment(0, 5);
+ anyButton.setLayoutData(data);
+
+ anysignedButton.setText(SecurityUIMsg.POLPAGE_BUTTON_ALLOW_ANY_SIGNED);
+ anysignedButton.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent event) {
+ //do nothing
+ }
+
+ public void widgetSelected(SelectionEvent event) {
+ expiredButton.setEnabled(true);
+ }
+ });
+ data = new FormData();
+ data.top = new FormAttachment(anyButton, 2);
+ data.left = new FormAttachment(0, 5);
+ anysignedButton.setLayoutData(data);
+
+ onlytrustedButton.setText(SecurityUIMsg.POLPAGE_BUTTON_ALLOW_ONLY_TRUSTED);
+ onlytrustedButton.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent event) {
+ //do nothing
+ }
+
+ public void widgetSelected(SelectionEvent event) {
+ expiredButton.setEnabled(true);
+ }
+
+ });
+ data = new FormData();
+ data.top = new FormAttachment(anysignedButton, 2);
+ data.left = new FormAttachment(0, 5);
+ onlytrustedButton.setLayoutData(data);
+ /*
+ whitelistButton.setText(STR_whiteList);
+ whitelistButton.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent event) {
+ //do nothing
+ }
+
+ public void widgetSelected(SelectionEvent event) {
+ whitelistTable.setEnabled(true);
+ promptButton.setEnabled(true);
+ }
+
+ });
+ data = new FormData();
+ data.top = new FormAttachment(anytrustedButton, 2);
+ data.left = new FormAttachment(0, 5);
+ whitelistButton.setLayoutData(data);
+
+ Composite whitelistArea = new Composite(loadArea, SWT.NONE);
+ whitelistArea.setLayout(new FormLayout());
+
+ data = new FormData();
+ data.top = new FormAttachment(whitelistButton, 2);
+ data.left = new FormAttachment(0, 25);
+ data.bottom = new FormAttachment(promptButton, -2);
+ data.right = new FormAttachment(100, 0);
+ whitelistArea.setLayoutData(data);
+
+ Button addButton = new Button(whitelistArea, SWT.PUSH);
+ addButton.setText("Add...");
+
+ data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ data.right = new FormAttachment(100, -5);
+ data.width = 100;
+ data.height = 25;
+ addButton.setLayoutData(data);
+
+ Button removeButton = new Button(whitelistArea, SWT.PUSH);
+ removeButton.setText("Remove");
+
+ data = new FormData();
+ data.top = new FormAttachment(addButton, 5);
+ data.right = new FormAttachment(100, -5);
+ data.width = 100;
+ data.height = 25;
+ removeButton.setLayoutData(data);
+
+ whitelistTable = new Table(whitelistArea, SWT.BORDER | SWT.V_SCROLL);
+ whitelistTable.setEnabled(false);
+ data = new FormData();
+ data.top = new FormAttachment(0, 0);
+ data.left = new FormAttachment(0, 0);
+ data.bottom = new FormAttachment(100, 0);
+ data.right = new FormAttachment(addButton, -5);
+ data.height = whitelistTable.getItemHeight() * 5;
+ whitelistTable.setLayoutData(data);
+
+ promptButton.setText(STR_promptUntrusted);
+ promptButton.setEnabled(false);
+ data = new FormData();
+ //data.top = new FormAttachment(whitelistTable, 10);
+ data.bottom = new FormAttachment(expiredButton, 0);
+ data.left = new FormAttachment(0, 5);
+ promptButton.setLayoutData(data);
+ */
+ expiredButton.setText(SecurityUIMsg.POLPAGE_BUTTON_ALLOW_EXPIRED);
+ data = new FormData();
+ data.top = new FormAttachment(onlytrustedButton, 5);
+ data.left = new FormAttachment(0, 5);
+ //data.bottom = new FormAttachment(100, -5);
+ expiredButton.setLayoutData(data);
+
+ onlytrustedButton.setSelection(true);
+ expiredButton.setEnabled(true);
+
+ return page;
+ }
+
+ public void init(IWorkbench workbench) {
+ this.noDefaultAndApplyButton();
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/SecurityCategoryPage.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/SecurityCategoryPage.java
new file mode 100644
index 0000000..35a5d6f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/preferences/SecurityCategoryPage.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.preferences;
+
+import org.eclipse.equinox.internal.security.ui.SecurityUIMsg;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.dialogs.PreferenceLinkArea;
+import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
+
+public class SecurityCategoryPage extends PreferencePage implements IWorkbenchPreferencePage {
+
+ public SecurityCategoryPage() {
+ //empty
+ }
+
+ public void init(IWorkbench workbench) {
+ this.noDefaultAndApplyButton();
+ }
+
+ protected Control createContents(Composite parent) {
+ Composite pageArea = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ pageArea.setLayout(layout);
+
+ PreferenceLinkArea policyLinkArea = new PreferenceLinkArea(pageArea, SWT.NONE, "org.eclipse.equinox.security.ui.policy", SecurityUIMsg.CATPAGE_LABEL_POLICY, (IWorkbenchPreferenceContainer) getContainer(), null); //$NON-NLS-1$
+ policyLinkArea.getControl().setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
+
+ PreferenceLinkArea certsLinkArea = new PreferenceLinkArea(pageArea, SWT.NONE, "org.eclipse.equinox.security.ui.certificates", SecurityUIMsg.CATPAGE_LABEL_CERTIFICATES, (IWorkbenchPreferenceContainer) getContainer(), null); //$NON-NLS-1$
+ certsLinkArea.getControl().setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
+
+ PreferenceLinkArea advancedLinkArea = new PreferenceLinkArea(pageArea, SWT.NONE, "org.eclipse.equinox.security.ui.advanced", SecurityUIMsg.CATPAGE_LABEL_ADVANCED, (IWorkbenchPreferenceContainer) getContainer(), null); //$NON-NLS-1$
+ advancedLinkArea.getControl().setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
+
+ return pageArea;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/DefaultPasswordProvider.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/DefaultPasswordProvider.java
new file mode 100644
index 0000000..ca6bd7a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/DefaultPasswordProvider.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.storage;
+
+import javax.crypto.spec.PBEKeySpec;
+import org.eclipse.equinox.internal.security.ui.nls.SecUIMessages;
+import org.eclipse.equinox.security.storage.provider.*;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * This password provider prompts user for the password. This provider uses the same password for
+ * all secure preferences.
+ */
+public class DefaultPasswordProvider extends PasswordProvider {
+
+ private PBEKeySpec password = null;
+
+ synchronized public PBEKeySpec login(IPreferencesContainer container) {
+ if (password != null)
+ return password;
+ String location = container.getLocation().getFile();
+ StorageLoginDialog loginDialog = new StorageLoginDialog(confirmPassword(container), location);
+ if (loginDialog.open() == Window.OK)
+ password = loginDialog.getGeneratedPassword();
+ return password;
+ }
+
+ synchronized public void logout(IPreferencesContainer container) {
+ if (password == null)
+ return;
+ password.clearPassword();
+ password = null;
+ }
+
+ private boolean confirmPassword(IPreferencesContainer container) {
+ if (!container.hasOption(IProviderHints.NEW_PASSWORD))
+ return false;
+ Object confirmationHint = container.getOption(IProviderHints.NEW_PASSWORD);
+ if (confirmationHint != null && confirmationHint instanceof Boolean)
+ return ((Boolean) confirmationHint).booleanValue();
+ return false;
+ }
+
+ public boolean changePassword(Exception e, IPreferencesContainer container) {
+ boolean canPrompt = true;
+ if (container.hasOption(IProviderHints.PROMPT_USER)) {
+ Object promptHint = container.getOption(IProviderHints.PROMPT_USER);
+ if (promptHint instanceof Boolean)
+ canPrompt = ((Boolean) promptHint).booleanValue();
+ }
+ if (!canPrompt)
+ return false;
+
+ MessageBox dialog = new MessageBox(new Shell(), SWT.ICON_ERROR | SWT.YES | SWT.NO);
+ dialog.setText(SecUIMessages.exceptionTitle);
+ dialog.setMessage(SecUIMessages.exceptionDecode);
+ int result = dialog.open();
+ return (result == SWT.YES);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/StorageLoginDialog.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/StorageLoginDialog.java
new file mode 100644
index 0000000..d3556a2
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/StorageLoginDialog.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.storage;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.spec.PBEKeySpec;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.equinox.internal.security.ui.Activator;
+import org.eclipse.equinox.internal.security.ui.nls.SecUIMessages;
+import org.eclipse.equinox.security.storage.EncodingUtils;
+import org.eclipse.jface.dialogs.*;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.ui.PlatformUI;
+
+public class StorageLoginDialog extends TitleAreaDialog {
+
+ private static final String DIALOG_SETTINGS_SECTION = "StorageLoginDialog"; //$NON-NLS-1$
+ private static final String HELP_ID = Activator.PLUGIN_ID + ".StorageLoginDialog"; //$NON-NLS-1$
+
+ private static final String DIGEST_ALGORITHM = "SHA"; //$NON-NLS-1$
+
+ protected Text password;
+ protected Text confirm;
+
+ protected Button showPassword;
+ protected Button okButton;
+
+ protected PBEKeySpec generatedPassword;
+
+ final protected boolean confirmPassword;
+ final protected String location;
+
+ public StorageLoginDialog(boolean confirmPassword, String location) {
+ super(null);
+ this.confirmPassword = confirmPassword;
+ this.location = location;
+ }
+
+ public PBEKeySpec getGeneratedPassword() {
+ return generatedPassword;
+ }
+
+ protected void createButtonsForButtonBar(Composite parent) {
+ okButton = createButton(parent, IDialogConstants.OK_ID, SecUIMessages.buttonLogin, true);
+ okButton.setEnabled(false);
+ createButton(parent, IDialogConstants.CANCEL_ID, SecUIMessages.buttonExit, false);
+ }
+
+ protected IDialogSettings getDialogBoundsSettings() {
+ IDialogSettings settings = Activator.getDefault().getDialogSettings();
+ IDialogSettings section = settings.getSection(DIALOG_SETTINGS_SECTION);
+ if (section == null)
+ section = settings.addNewSection(DIALOG_SETTINGS_SECTION);
+ return section;
+ }
+
+ protected boolean isResizable() {
+ return true;
+ }
+
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ if (location == null)
+ shell.setText(SecUIMessages.dialogTitle);
+ else
+ shell.setText(location);
+
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, HELP_ID);
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite) super.createDialogArea(parent);
+
+ setMessage(SecUIMessages.messageLogin);
+
+ new Label(composite, SWT.LEFT).setText(SecUIMessages.labelPassword);
+ password = new Text(composite, SWT.LEFT | SWT.BORDER);
+ password.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent event) {
+ okButton.setEnabled(validatePassword());
+ }
+ });
+
+ if (confirmPassword) {
+ new Label(composite, SWT.LEFT).setText(SecUIMessages.labelConfirm);
+ confirm = new Text(composite, SWT.LEFT | SWT.BORDER);
+ confirm.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent event) {
+ okButton.setEnabled(validatePassword());
+ }
+ });
+ } else
+ confirm = null;
+
+ showPassword = new Button(composite, SWT.CHECK);
+ showPassword.setText(SecUIMessages.showPassword);
+ showPassword.addSelectionListener(new SelectionListener() {
+ public void widgetSelected(SelectionEvent e) {
+ passwordVisibility();
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ passwordVisibility();
+ }
+ });
+
+ // by default don't display password as clear text
+ showPassword.setSelection(false);
+ passwordVisibility();
+
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ GridLayoutFactory.swtDefaults().generateLayout(composite);
+
+ return composite;
+ }
+
+ protected void passwordVisibility() {
+ boolean selected = showPassword.getSelection();
+ if (selected) {
+ password.setEchoChar('\0');
+ if (confirm != null)
+ confirm.setEchoChar('\0');
+ } else {
+ password.setEchoChar('*');
+ if (confirm != null)
+ confirm.setEchoChar('*');
+ }
+ }
+
+ protected boolean validatePassword() {
+ String password1 = password.getText();
+ if ((password1 == null) || (password1.length() == 0)) {
+ setMessage(SecUIMessages.messageEmptyPassword, IMessageProvider.ERROR);
+ return false;
+ }
+ if (confirm != null) {
+ String password2 = confirm.getText();
+ if (!password1.equals(password2)) {
+ setMessage(SecUIMessages.messageNoMatch, IMessageProvider.WARNING);
+ return false;
+ }
+ }
+ setMessage(SecUIMessages.messageLogin, IMessageProvider.NONE);
+ return true;
+ }
+
+ protected void okPressed() {
+ String internalPassword;
+ try {
+ // normally use digest of what was entered
+ MessageDigest digest = MessageDigest.getInstance(DIGEST_ALGORITHM);
+ byte[] digested = digest.digest(new String(password.getText()).getBytes());
+ internalPassword = EncodingUtils.encodeBase64(digested);
+ } catch (NoSuchAlgorithmException e) {
+ // just use the text as is
+ Activator.log(IStatus.WARNING, SecUIMessages.noDigestPassword, new Object[] {DIGEST_ALGORITHM}, e);
+ internalPassword = password.getText();
+ }
+ generatedPassword = new PBEKeySpec(internalPassword.toCharArray());
+
+ super.okPressed();
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportCertSelectPage.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportCertSelectPage.java
new file mode 100644
index 0000000..a42869d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportCertSelectPage.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.wizard;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.security.cert.*;
+import java.util.*;
+import java.util.List;
+import org.eclipse.equinox.internal.security.ui.SecurityUIMsg;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.*;
+
+public class CertificateImportCertSelectPage extends WizardPage implements Listener {
+
+ private Composite certPreview;
+ private Combo certDropDown;
+ private List certList;
+
+ static CertificateFactory certFact;
+
+ static {
+ try {
+ certFact = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$
+ } catch (CertificateException e) {
+ // TODO log error here
+ }
+ }
+
+ protected CertificateImportCertSelectPage(String pageName) {
+ super(pageName);
+ setTitle(SecurityUIMsg.WIZARD_SELECT_CERT);
+ setDescription(SecurityUIMsg.WIZARD_SELECT_CERT_FROM_DROP_DOWN);
+ }
+
+ public void createControl(Composite parent) {
+ Composite certSelectComposite = new Composite(parent, SWT.NONE);
+ setControl(certSelectComposite);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 1;
+ layout.makeColumnsEqualWidth = false;
+ certSelectComposite.setLayout(layout);
+ certSelectComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
+
+ certDropDown = new Combo(certSelectComposite, SWT.DROP_DOWN | SWT.READ_ONLY);
+ certDropDown.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL));
+
+ // populate the drop down
+ populateDropDown();
+
+ certPreview = new Composite(certSelectComposite, SWT.None);
+ certPreview.setLayout(new GridLayout());
+ GridData gd = new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL);
+ // gd.horizontalSpan = 2;
+ certPreview.setLayoutData(gd);
+ }
+
+ private void populateDropDown() {
+ CertificateImportWizard certImportWizard = (CertificateImportWizard) getWizard();
+ if (certImportWizard.selectedImportFile == null)
+ return;
+
+ if (certDropDown.getItemCount() > 0)
+ certDropDown.removeAll();
+
+ try {
+ certList = new ArrayList();
+ Collection collection = certFact.generateCertificates(new FileInputStream(certImportWizard.selectedImportFile));
+ // For a set or list
+ for (Iterator it = collection.iterator(); it.hasNext();) {
+ certList.add(it.next());
+ }
+
+ } catch (CertificateException e) {
+ setErrorMessage(e.getMessage());
+ } catch (FileNotFoundException e) {
+ setErrorMessage(e.getMessage());
+ }
+
+ for (int i = 0; i < certList.size(); i++) {
+ X509Certificate x509Cert = (X509Certificate) certList.get(i);
+ String subjectDN = x509Cert.getSubjectDN().getName();
+ certDropDown.add(subjectDN);
+ }
+ certDropDown.addListener(SWT.Selection, this);
+
+ }
+
+ public void handleEvent(Event e) {
+ if (e.widget == certDropDown) {
+ // populate the preview with select cert info
+ X509Certificate x509Cert = (X509Certificate) certList.get(certDropDown.getSelectionIndex());
+ showCertificate(x509Cert);
+ ((CertificateImportWizard) getWizard()).selectCert = x509Cert;
+ getWizard().getContainer().updateButtons();
+ }
+ }
+
+ public void showCertificate(X509Certificate cert) {
+ Control ctrls[] = certPreview.getChildren();
+ for (int i = 0; i < ctrls.length; i++) {
+ ctrls[i].dispose();
+ }
+ CertificateViewer certViewer = new CertificateViewer(certPreview);
+ certViewer.setCertificate(cert);
+ certPreview.layout();
+ }
+
+ /**
+ * This methods get called before each page gets showed
+ */
+ public void setVisible(boolean visible) {
+ if (visible)
+ populateDropDown();
+ super.setVisible(visible);
+
+ }
+
+ public boolean canFlipToNextPage() {
+ return ((CertificateImportWizard) getWizard()).selectCert != null;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportConfirmationPage.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportConfirmationPage.java
new file mode 100644
index 0000000..65fe309
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportConfirmationPage.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.wizard;
+
+import org.eclipse.equinox.internal.security.ui.SecurityUIMsg;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+public class CertificateImportConfirmationPage extends WizardPage {
+
+ private CertificateViewer certViewer;
+ private Label trustEngineLabel;
+ private Composite composite;
+
+ protected CertificateImportConfirmationPage(String pageName) {
+ super(pageName);
+ setTitle(SecurityUIMsg.WIZARD_IMPORT_CONFIRMATION_TITLE);
+ setDescription(SecurityUIMsg.WIZARD_IMPORT_CONFIRMATION_MSG);
+ }
+
+ public void createControl(Composite parent) {
+ composite = new Composite(parent, SWT.NONE);
+ setControl(composite);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 1;
+ layout.makeColumnsEqualWidth = false;
+ layout.marginWidth = 0;
+ composite.setLayout(layout);
+ composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ certViewer = new CertificateViewer(composite);
+ trustEngineLabel = new Label(composite, SWT.None);
+ trustEngineLabel.setText(""); //$NON-NLS-1$
+ }
+
+ public void setVisible(boolean visible) {
+ if (visible) {
+ CertificateImportWizard certImporWiz = (CertificateImportWizard) getWizard();
+ certViewer.setCertificate(certImporWiz.selectCert);
+ trustEngineLabel.setText(certImporWiz.selectTrustEngine.getName());
+ composite.layout();
+ }
+ super.setVisible(visible);
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportFileSelectPage.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportFileSelectPage.java
new file mode 100644
index 0000000..3914100
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportFileSelectPage.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.wizard;
+
+import java.io.File;
+import org.eclipse.equinox.internal.security.ui.SecurityUIMsg;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.*;
+
+public class CertificateImportFileSelectPage extends WizardPage implements Listener {
+
+ private Button browseDirectoriesButton;
+ private Text filePathField;
+
+ protected CertificateImportFileSelectPage(String pageName) {
+ super(pageName);
+ setTitle(pageName);
+ setDescription(SecurityUIMsg.WIZARD_TITLE_FILE_SELECT);
+ }
+
+ public void createControl(Composite parent) {
+ Composite certSelectComposite = new Composite(parent, SWT.NONE);
+ setControl(certSelectComposite);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 3;
+ layout.makeColumnsEqualWidth = false;
+ layout.marginWidth = 0;
+ certSelectComposite.setLayout(layout);
+ certSelectComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ // new project from directory radio button
+ Label certSelectLabel = new Label(certSelectComposite, SWT.RADIO);
+ certSelectLabel.setText(SecurityUIMsg.WIZARD_SELECT_FILE);
+
+ // project location entry field
+ this.filePathField = new Text(certSelectComposite, SWT.BORDER);
+
+ this.filePathField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
+
+ // browse button
+ browseDirectoriesButton = new Button(certSelectComposite, SWT.PUSH);
+ browseDirectoriesButton.setText(SecurityUIMsg.WIZARD_BROWSE);
+ browseDirectoriesButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ handleLocationFileButtonPressed();
+ }
+ });
+
+ addListeners();
+ }
+
+ private void addListeners() {
+ browseDirectoriesButton.addListener(SWT.Selection, this);
+ filePathField.addListener(SWT.KeyUp, this);
+ }
+
+ /**
+ * The browse button has been selected. Select the location.
+ */
+ protected void handleLocationFileButtonPressed() {
+ final FileDialog certFileDialog = new FileDialog(filePathField.getShell(), SWT.OPEN);
+ certFileDialog.setText(SecurityUIMsg.WIZARD_SELECT_FILE);
+ certFileDialog.setFilterPath(filePathField.getText());
+ certFileDialog.setFilterExtensions(new String[] {"*.cer", "*.p7b", "*.der"}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ String selectedCert = certFileDialog.open();
+ if (selectedCert != null) {
+ filePathField.setText(selectedCert);
+ }
+ }
+
+ public boolean canFlipToNextPage() {
+ return (filePathField.getText().length() < 1 || null != getErrorMessage()) ? false : true;
+ }
+
+ public void handleEvent(Event e) {
+ if (e.widget == browseDirectoriesButton || e.widget == filePathField)
+ if (filePathField.getText().length() < 1)
+ setErrorMessage(SecurityUIMsg.WIZARD_ERROR_CERT_REQUIRED);
+ else
+ setErrorMessage(null);
+ getWizard().getContainer().updateButtons();
+ }
+
+ public IWizardPage getNextPage() {
+ File file = new File(filePathField.getText().trim());
+ if (file.isDirectory() || !file.exists()) {
+ setErrorMessage(NLS.bind(SecurityUIMsg.WIZARD_FILE_NOT_FOUND, new String[] {filePathField.getText()}));
+ return null;
+ }
+ saveFileSelection();
+
+ return super.getNextPage();
+ }
+
+ private void saveFileSelection() {
+ CertificateImportWizard certImportWizard = (CertificateImportWizard) getWizard();
+ certImportWizard.selectedImportFile = filePathField.getText().trim();
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportTrustEngineSelectPage.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportTrustEngineSelectPage.java
new file mode 100644
index 0000000..a3bb923
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportTrustEngineSelectPage.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.wizard;
+
+import org.eclipse.equinox.internal.security.ui.Activator;
+import org.eclipse.equinox.internal.security.ui.SecurityUIMsg;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.service.security.TrustEngine;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.*;
+
+public class CertificateImportTrustEngineSelectPage extends WizardPage implements Listener {
+
+ private Text aliasField;
+ private Combo trustEngineCombo;
+ private TrustEngine trustEngines[];
+
+ protected CertificateImportTrustEngineSelectPage(String pageName) {
+ super(pageName);
+ setTitle(SecurityUIMsg.WIZARD_ENGINE_SELECT_TITLE);
+ setDescription(SecurityUIMsg.WIZARD_ENGINE_SELECT_MSG);
+ }
+
+ public void createControl(Composite parent) {
+ Composite certSelectComposite = new Composite(parent, SWT.NONE);
+ setControl(certSelectComposite);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 2;
+ layout.makeColumnsEqualWidth = false;
+ layout.marginWidth = 0;
+ certSelectComposite.setLayout(layout);
+ certSelectComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ Label aliasLabel = new Label(certSelectComposite, SWT.None);
+ aliasLabel.setText(SecurityUIMsg.WIZARD_ALIAS_NAME_FIELD);
+
+ aliasField = new Text(certSelectComposite, SWT.None);
+ aliasField.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL));
+
+ /*
+ * create the trust engine area
+ */
+ Label targetEngineLabel = new Label(certSelectComposite, SWT.None);
+ targetEngineLabel.setText(SecurityUIMsg.WIZARD_TARGET_TRUST_ENGINE);
+
+ trustEngineCombo = new Combo(certSelectComposite, SWT.DROP_DOWN | SWT.READ_ONLY);
+
+ trustEngines = Activator.getTrustEngines();
+
+ // get a list of trust engine and fill the combo
+ for (int i = 0; i < trustEngines.length; i++) {
+ if (!trustEngines[i].isReadOnly())
+ trustEngineCombo.add(trustEngines[i].getName());
+
+ }
+ if (trustEngineCombo.getItemCount() == 0)
+ setErrorMessage(SecurityUIMsg.WIZARD_ERROR_NO_WRITE_ENGINE);
+ else
+ trustEngineCombo.setVisibleItemCount(trustEngines.length);
+
+ addListeners();
+ }
+
+ private void addListeners() {
+ aliasField.addListener(SWT.KeyUp, this);
+ trustEngineCombo.addListener(SWT.Selection, this);
+ }
+
+ public void handleEvent(Event e) {
+ if (e.widget == aliasField) {
+ if (aliasField.getText().length() < 1) {
+ setErrorMessage(SecurityUIMsg.WIZARD_ERROR_ALIAS_REQUIRED);
+ } else {
+ setErrorMessage(null);
+ ((CertificateImportWizard) getWizard()).aliasName = aliasField.getText();
+ }
+ }
+
+ if (e.widget == trustEngineCombo) {
+ if (trustEngineCombo.getSelectionIndex() == -1) {
+ setErrorMessage(SecurityUIMsg.WIZARD_ERROR_ENGINE_REQUIRED);
+ } else {
+ setErrorMessage(null);
+ ((CertificateImportWizard) getWizard()).selectTrustEngine = trustEngines[trustEngineCombo.getSelectionIndex()];
+ }
+ }
+ getWizard().getContainer().updateButtons();
+ }
+
+ public boolean canFlipToNextPage() {
+ return (aliasField.getText().length() > 0) && (trustEngineCombo.getSelectionIndex() != -1);
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportWizard.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportWizard.java
new file mode 100644
index 0000000..8c5cdf4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateImportWizard.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.wizard;
+
+import java.security.cert.X509Certificate;
+import org.eclipse.equinox.internal.security.ui.SecurityUIMsg;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.osgi.service.security.TrustEngine;
+import org.eclipse.ui.IImportWizard;
+import org.eclipse.ui.IWorkbench;
+
+public class CertificateImportWizard extends Wizard implements IImportWizard {
+
+ // ImportWizardPage mainPage;
+ CertificateImportFileSelectPage selectCertFilePage;
+ CertificateImportCertSelectPage selectCertPage;
+ CertificateImportTrustEngineSelectPage selectTrustEnginePage;
+ CertificateImportConfirmationPage certConfirmPage;
+
+ String selectedImportFile;
+ String aliasName;
+ X509Certificate selectCert;
+ TrustEngine selectTrustEngine;
+
+ public CertificateImportWizard() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchWizard#init(org.eclipse.ui.IWorkbench, org.eclipse.jface.viewers.IStructuredSelection)
+ */
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ //nothing
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.IWizard#addPages()
+ */
+ public void addPages() {
+ // mainPage = new ImportWizardPage(SecurityUIMsg.IMPORT_FILE); //NON-NLS-1
+ // addPage(mainPage);
+
+ selectCertFilePage = new CertificateImportFileSelectPage(SecurityUIMsg.WIZARD_PAGE_FILE_CERT_SELECT);
+ addPage(selectCertFilePage);
+
+ selectCertPage = new CertificateImportCertSelectPage(SecurityUIMsg.WIZARD_PAGE_CERT_SELECT);
+ addPage(selectCertPage);
+
+ selectTrustEnginePage = new CertificateImportTrustEngineSelectPage(SecurityUIMsg.WIZARD_PAGE_ENGINE);
+ addPage(selectTrustEnginePage);
+
+ certConfirmPage = new CertificateImportConfirmationPage(SecurityUIMsg.WIZARD_IMPORT_CONFIRMATION_TITLE);
+ addPage(certConfirmPage);
+ }
+
+ public boolean canFinish() {
+ return getContainer().getCurrentPage() == certConfirmPage;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#performFinish()
+ */
+ public boolean performFinish() {
+ try {
+ selectTrustEngine.addTrustAnchor(selectCert, aliasName);
+ } catch (Exception e) {
+ certConfirmPage.setErrorMessage(e.getMessage());
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateViewer.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateViewer.java
new file mode 100644
index 0000000..61176b4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/CertificateViewer.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.ui.wizard;
+
+import java.security.cert.Certificate;
+import org.eclipse.equinox.internal.security.ui.*;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.*;
+
+public class CertificateViewer {
+
+ private Composite composite;
+
+ private TableViewer tableViewer;
+
+ public CertificateViewer(Composite parent) {
+ composite = new Composite(parent, SWT.None);
+ composite.setLayout(new GridLayout());
+
+ tableViewer = new TableViewer(composite, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+ Table table = tableViewer.getTable();
+ table.setHeaderVisible(true);
+ GridData tableData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
+ table.setLayoutData(tableData);
+
+ TableColumn propertyCol = new TableColumn(table, SWT.LEFT);
+ propertyCol.setText(SecurityUIMsg.STR_CERT_VIEWER_FIELD);
+ propertyCol.setWidth(200);
+
+ TableColumn valueCol = new TableColumn(table, SWT.LEFT);
+ valueCol.setText(SecurityUIMsg.STR_CERT_VIEWER_VALUE);
+ valueCol.setWidth(300);
+ }
+
+ public void setCertificate(Certificate certificate) {
+ tableViewer.setContentProvider(new X509CertificateAttributeContentProvider());
+ tableViewer.setLabelProvider(new X509CertificateAttributeLabelProvider());
+ tableViewer.setInput(certificate);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/messages.properties b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/messages.properties
new file mode 100644
index 0000000..3aa5cfa
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/wizard/messages.properties
@@ -0,0 +1 @@
+SelectCertificatePage_WIZARD_SELECT_CERT_FROM_DROP_DOWN=Please select a certificate from the drop down
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/security/ui/actions/SecurityContributionItemFactory.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/security/ui/actions/SecurityContributionItemFactory.java
new file mode 100644
index 0000000..c96e532
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/security/ui/actions/SecurityContributionItemFactory.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.ui.actions;
+
+import org.eclipse.equinox.internal.security.ui.SecurityStatusControl;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.actions.ContributionItemFactory;
+
+public abstract class SecurityContributionItemFactory extends ContributionItemFactory {
+
+ protected SecurityContributionItemFactory(String contributionItemId) {
+ super(contributionItemId);
+ }
+
+ /**
+ * Workbench contribution item (id "securityStatus"): An icon for
+ * evaluating and inspecting the security status of the system.
+ * @since 3.4
+ */
+ public static final ContributionItemFactory SECURITY_STATUS = new ContributionItemFactory("securityStatus") {//$NON-NLS-1$
+ public IContributionItem create(IWorkbenchWindow window) {
+ if (window == null) {
+ throw new IllegalArgumentException();
+ }
+ return new SecurityStatusControl(window, getId());
+ }
+ };
+}
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/security/ui/services/AuthorizationManager.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/security/ui/services/AuthorizationManager.java
new file mode 100644
index 0000000..81fb977
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/security/ui/services/AuthorizationManager.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.ui.services;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * The AuthorizationManager is the facility by which the end user
+ * is informed of the current state of the system with respect to
+ * bundle authorization based security.
+ */
+public abstract class AuthorizationManager {
+
+ /**
+ * Query whether the authorization system is enabled for the system.
+ *
+ * @return <code>true</code> if and only if authorization is enabled
+ */
+ abstract public boolean isEnabled();
+
+ /**
+ * Returns true when the system is in need of attention from the end
+ * user. This means that some unauthorized content has been encountered, and the
+ * user has not yet inspected the situation.
+ *
+ * @return <code>true</code> if user attention is required
+ */
+ abstract public boolean needsAttention();
+
+ /**
+ * Return an Eclipse IStatus object representing the current state of the
+ * authorization system.
+ *
+ * @return IStatus code representing the system status
+ */
+ abstract public IStatus getStatus();
+
+ /**
+ * Open the authorization manager user interface so that the end
+ * user can view and edit the system's authorization state.
+ *
+ * @param workbenchWindow the workbench window
+ */
+ abstract public void displayManager(IWorkbenchWindow workbenchWindow);
+
+}
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/.classpath b/bundles/org.eclipse.equinox.security.win32.x86/.classpath
new file mode 100644
index 0000000..065ac06
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/.project b/bundles/org.eclipse.equinox.security.win32.x86/.project
new file mode 100644
index 0000000..fd6e4d9
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.equinox.security.win32.x86</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.security.win32.x86/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..743005f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Tue Jan 08 16:13:49 EST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.source=1.3
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.security.win32.x86/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..869e118
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/META-INF/MANIFEST.MF
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %fragmentName
+Bundle-SymbolicName: org.eclipse.equinox.security.win32.x86;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: %providerName
+Fragment-Host: org.eclipse.equinox.security;bundle-version="[1.0.0,2.0.0)"
+Bundle-RequiredExecutionEnvironment: J2SE-1.4
+Bundle-Localization: fragment
+Eclipse-PlatformFilter: (& (osgi.os=win32) (osgi.arch=x86))
+Export-Package: org.eclipse.equinox.internal.security.win32;x-internal:=true
+Require-Bundle: org.eclipse.swt;bundle-version="3.4.0";resolution:=optional
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/about.html b/bundles/org.eclipse.equinox.security.win32.x86/about.html
new file mode 100644
index 0000000..4602330
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 2, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/build.properties b/bundles/org.eclipse.equinox.security.win32.x86/build.properties
new file mode 100644
index 0000000..f8c2037
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/build.properties
@@ -0,0 +1,12 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ fragment.properties,\
+ fragment.xml,\
+ about.html,\
+ jnicrypt.dll
+src.includes = cpp/,\
+ META-INF/,\
+ about.html,\
+ src/
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/cpp/ReadMe.txt b/bundles/org.eclipse.equinox.security.win32.x86/cpp/ReadMe.txt
new file mode 100644
index 0000000..b5f137c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/cpp/ReadMe.txt
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+This is a JNI bridge to access native Windows encryption methods from Java. The methods
+perform user-specific encryption of the data. The same user can later decrypt data using
+methods provided by this DLL. A different user won't be able to decrypt the data.
+
+If the user has a roaming profile, he can decrypt data on a different computer in the domain.
+
+In the event if stand-alone computer needs to have OS re-installed (or the domain controller
+and the computer in the domain), be sure to create Windows password recovery disk BEFORE
+re-installing the operating system.
+
+Note that this mechanism is intended to be used with small size data (i.e., passwords). For
+large amount of data consider encrypting your password using this mechanism and using
+symmetric encryption to encrypt the data.
+
+To compile this DLL:
+=> JAVA_HOME environment variable needs to be setup so that jni.h can be found
+
+Note C++ projects settings:
+=> Additional include directories - "$(JAVA_HOME)/include";"$(JAVA_HOME)/include/win32"
+=> Additional linker dependency - Crypt32.lib
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/cpp/jnicrypt.cpp b/bundles/org.eclipse.equinox.security.win32.x86/cpp/jnicrypt.cpp
new file mode 100644
index 0000000..9a8f2c4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/cpp/jnicrypt.cpp
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+#include <windows.h>
+#include <wincrypt.h>
+#include "jnicrypt.h"
+
+BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
+{
+ return TRUE;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_org_eclipse_equinox_internal_security_win32_WinCrypto_winencrypt
+ (JNIEnv *env, jobject obj, jbyteArray value)
+{
+ jsize size = env->GetArrayLength(value);
+ jbyte *body = env->GetByteArrayElements(value, NULL);
+ if (body == NULL)
+ return NULL;
+
+ DATA_BLOB clearText;
+ DATA_BLOB encryptedText;
+ clearText.pbData = (BYTE*) body;
+ clearText.cbData = (DWORD) size;
+
+ BOOL result = CryptProtectData(&clearText, L"Equinox", NULL, NULL, NULL, 0, &encryptedText);
+
+ // release memory allocated by Java environment
+ env->ReleaseByteArrayElements(value, body, 0);
+
+ if (result == FALSE)
+ return NULL;
+
+ jbyteArray returnArray = env->NewByteArray(encryptedText.cbData);
+ env->SetByteArrayRegion(returnArray, 0, encryptedText.cbData, (jbyte*) encryptedText.pbData);
+ LocalFree(encryptedText.pbData); // no need any more, have Java representation
+
+ return returnArray;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_org_eclipse_equinox_internal_security_win32_WinCrypto_windecrypt
+ (JNIEnv *env, jobject obj, jbyteArray value)
+{
+ jsize size = env->GetArrayLength(value);
+ jbyte *body = env->GetByteArrayElements(value, NULL);
+ if (body == NULL)
+ return NULL;
+
+ DATA_BLOB clearText;
+ DATA_BLOB encryptedText;
+ encryptedText.pbData = (BYTE*) body;
+ encryptedText.cbData = (DWORD) size;
+
+ LPWSTR pDescrOut = NULL;
+ BOOL result = CryptUnprotectData(&encryptedText, &pDescrOut, NULL, NULL, NULL, 0, &clearText);
+
+ if (pDescrOut != NULL)
+ LocalFree(pDescrOut);
+
+ // release memory allocated by Java environment
+ env->ReleaseByteArrayElements(value, body, 0);
+
+ if (result == FALSE)
+ return NULL;
+
+ jbyteArray returnArray = env->NewByteArray(clearText.cbData);
+ env->SetByteArrayRegion(returnArray, 0, clearText.cbData, (jbyte*) clearText.pbData);
+ LocalFree(clearText.pbData); // no need any more, have Java representation
+
+ return returnArray;
+}
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/cpp/jnicrypt.h b/bundles/org.eclipse.equinox.security.win32.x86/cpp/jnicrypt.h
new file mode 100644
index 0000000..9d44ffe
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/cpp/jnicrypt.h
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+#include <jni.h>
+
+#ifndef EQUINOX_WIN32_CRYPTO
+#define EQUINOX_WIN32_CRYPTO
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT jbyteArray JNICALL Java_org_eclipse_equinox_internal_security_win32_WinCrypto_windecrypt(JNIEnv *, jobject, jbyteArray);
+JNIEXPORT jbyteArray JNICALL Java_org_eclipse_equinox_internal_security_win32_WinCrypto_winencrypt(JNIEnv *, jobject, jbyteArray);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // #ifndef EQUINOX_WIN32_CRYPTO
+
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/cpp/jnicrypt.vcproj b/bundles/org.eclipse.equinox.security.win32.x86/cpp/jnicrypt.vcproj
new file mode 100644
index 0000000..c207c57
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/cpp/jnicrypt.vcproj
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="jnicrypt"
+ ProjectGUID="{F34C755E-2053-4783-85FC-356BC2CE2A35}"
+ RootNamespace="jnicrypt"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""$(JAVA_HOME)/include";"$(JAVA_HOME)/include/win32""
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;JNICRYPT_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Crypt32.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""$(JAVA_HOME)/include";"$(JAVA_HOME)/include/win32""
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;JNICRYPT_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Crypt32.lib"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\jnicrypt.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\jnicrypt.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <File
+ RelativePath=".\ReadMe.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/fragment.properties b/bundles/org.eclipse.equinox.security.win32.x86/fragment.properties
new file mode 100644
index 0000000..79c7758
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/fragment.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2008 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+fragmentName = Windows Data Protection services integration
+providerName = Eclipse.org
+moduleName = Password provider backed by the Windows Data Protection API (DPAPI)
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/fragment.xml b/bundles/org.eclipse.equinox.security.win32.x86/fragment.xml
new file mode 100644
index 0000000..bb3899f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/fragment.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<fragment>
+ <extension
+ id="WindowsPasswordProvider"
+ name="%moduleName"
+ point="org.eclipse.equinox.security.secureStorage">
+ <provider
+ class="org.eclipse.equinox.internal.security.win32.WinCrypto"
+ priority="5">
+ </provider>
+ </extension>
+
+</fragment>
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/jnicrypt.dll b/bundles/org.eclipse.equinox.security.win32.x86/jnicrypt.dll
new file mode 100644
index 0000000..bbfbafa
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/jnicrypt.dll
Binary files differ
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/WinCrypto.java b/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/WinCrypto.java
new file mode 100644
index 0000000..724fe80
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/WinCrypto.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.win32;
+
+import java.io.IOException;
+import java.security.SecureRandom;
+
+import javax.crypto.spec.PBEKeySpec;
+
+import org.eclipse.equinox.internal.security.auth.AuthPlugin;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.equinox.internal.security.storage.Base64;
+import org.eclipse.equinox.internal.security.win32.nls.WinCryptoMessages;
+import org.eclipse.equinox.security.storage.ISecurePreferences;
+import org.eclipse.equinox.security.storage.StorageException;
+import org.eclipse.equinox.security.storage.provider.IPreferencesContainer;
+import org.eclipse.equinox.security.storage.provider.IProviderHints;
+import org.eclipse.equinox.security.storage.provider.PasswordProvider;
+
+/**
+ * Provides interface with native Windows data protection API. This provider
+ * auto-generates separate passwords for each secure preferences tree.
+ */
+public class WinCrypto extends PasswordProvider {
+
+ native public byte[] windecrypt(byte[] encryptedText);
+
+ native public byte[] winencrypt(byte[] clearText);
+
+ static {
+ System.loadLibrary("jnicrypt");
+ }
+
+ private final static String WIN_PROVIDER_NODE = "/org.eclipse.equinox.secure.storage/windows";
+ private final static String PASSWORD_KEY = "encryptedPassword";
+
+ /**
+ * The length of the randomly generated password in bytes
+ */
+ private final static int PASSWORD_LENGTH = 250;
+
+ public PBEKeySpec login(IPreferencesContainer container) {
+ byte[] encryptedPassord = getEncryptedPassword(container);
+ if (encryptedPassord != null) {
+ byte[] decryptedPassword = windecrypt(encryptedPassord);
+ if (decryptedPassword != null) {
+ String password = new String(decryptedPassword);
+ return new PBEKeySpec(password.toCharArray());
+ } else {
+ StorageException e = new StorageException(StorageException.ENCRYPTION_ERROR, WinCryptoMessages.decryptPasswordFailed);
+ AuthPlugin.getDefault().logError(WinCryptoMessages.decryptPasswordFailed, e);
+
+ if (container.hasOption(IProviderHints.PROMPT_USER)) {
+ Object promptHint = container.getOption(IProviderHints.PROMPT_USER);
+ if (promptHint instanceof Boolean) {
+ boolean canPrompt = ((Boolean) promptHint).booleanValue();
+ if (!canPrompt)
+ return null;
+ }
+ }
+ try {
+ if (!WinCryptoUI.canRecreatePassword())
+ return null;
+ } catch (ClassNotFoundException exception) {
+ return null;
+ }
+ // follow down with new password generation
+ }
+ }
+
+ // add info message in the log
+ AuthPlugin.getDefault().logMessage(WinCryptoMessages.newPasswordGenerated);
+
+ byte[] rawPassword = new byte[PASSWORD_LENGTH];
+ SecureRandom random = new SecureRandom();
+ random.setSeed(System.currentTimeMillis());
+ random.nextBytes(rawPassword);
+ String password = Base64.encode(rawPassword);
+ if (savePassword(password, container))
+ return new PBEKeySpec(password.toCharArray());
+ else
+ return null;
+ }
+
+ private byte[] getEncryptedPassword(IPreferencesContainer container) {
+ ISecurePreferences node = container.getPreferences().node(WIN_PROVIDER_NODE);
+ String passwordHint;
+ try {
+ passwordHint = node.get(PASSWORD_KEY, null);
+ } catch (StorageException e) { // should never happen in this scenario
+ AuthPlugin.getDefault().logError(WinCryptoMessages.decryptPasswordFailed, e);
+ return null;
+ }
+ if (passwordHint == null)
+ return null;
+ return Base64.decode(passwordHint);
+ }
+
+ private boolean savePassword(String password, IPreferencesContainer container){
+ byte[] data = winencrypt(password.getBytes());
+ if (data == null) { // this is bad. Something wrong with OS or JNI.
+ StorageException e = new StorageException(StorageException.ENCRYPTION_ERROR, WinCryptoMessages.encryptPasswordFailed);
+ AuthPlugin.getDefault().logError(WinCryptoMessages.encryptPasswordFailed, e);
+ return false;
+ }
+ String encodedEncryptyedPassword = Base64.encode(data);
+ ISecurePreferences node = container.getPreferences().node(WIN_PROVIDER_NODE);
+ try {
+ node.put(PASSWORD_KEY, encodedEncryptyedPassword, false); // note we don't recursively try to encrypt
+ } catch (StorageException e) { // should never happen in this scenario
+ AuthPlugin.getDefault().logError(SecAuthMessages.errorOnSave, e);
+ return false;
+ }
+ try {
+ node.flush(); // save right away
+ } catch (IOException e) {
+ AuthPlugin.getDefault().logError(SecAuthMessages.errorOnSave, e);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean changePassword(Exception e, IPreferencesContainer container) {
+ // It would be rather dangerous to allow this password to be changed
+ // as it would permanently trash all entries in the secure storage.
+ // Rather applications using get...() should handle exceptions and offer to overwrite
+ // data on an entry-by-entry scale.
+ return false;
+ }
+
+ public void logout(IPreferencesContainer container) {
+ // nothing to do
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/WinCryptoUI.java b/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/WinCryptoUI.java
new file mode 100644
index 0000000..83f2cbc
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/WinCryptoUI.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.win32;
+
+import org.eclipse.equinox.internal.security.win32.nls.WinCryptoMessages;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Isolates optional UI functionality
+ */
+public class WinCryptoUI {
+
+ public static boolean canRecreatePassword() throws ClassNotFoundException{
+ MessageBox dialog = new MessageBox(new Shell(), SWT.ICON_ERROR | SWT.YES | SWT.NO);
+ dialog.setText(WinCryptoMessages.newPasswordTitle);
+ dialog.setMessage(WinCryptoMessages.newPasswordMessage);
+ int result = dialog.open();
+ return (result == SWT.YES);
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/nls/WinCryptoMessages.java b/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/nls/WinCryptoMessages.java
new file mode 100644
index 0000000..d14c2a4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/nls/WinCryptoMessages.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.win32.nls;
+
+import org.eclipse.osgi.util.NLS;
+
+public class WinCryptoMessages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.equinox.internal.security.win32.nls.messages"; //$NON-NLS-1$
+
+ // Windows module
+ public static String encryptPasswordFailed;
+ public static String decryptPasswordFailed;
+ public static String newPasswordTitle;
+ public static String newPasswordMessage;
+ public static String newPasswordGenerated;
+
+ static {
+ // load message values from bundle file
+ reloadMessages();
+ }
+
+ public static void reloadMessages() {
+ NLS.initializeMessages(BUNDLE_NAME, WinCryptoMessages.class);
+ }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/nls/messages.properties b/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/nls/messages.properties
new file mode 100644
index 0000000..1f204f2
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security.win32.x86/src/org/eclipse/equinox/internal/security/win32/nls/messages.properties
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2008 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+
+## Windows module
+encryptPasswordFailed = Unable to encrypt master password for storage.
+decryptPasswordFailed = Unable to decrypt master password.
+newPasswordTitle = Keyring password
+newPasswordMessage = Unable to retrieve keyring password. Would you like to generate new keyring password?
+newPasswordGenerated = New keyring password generated.
diff --git a/bundles/org.eclipse.equinox.security/.classpath b/bundles/org.eclipse.equinox.security/.classpath
new file mode 100644
index 0000000..065ac06
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.equinox.security/.options b/bundles/org.eclipse.equinox.security/.options
new file mode 100644
index 0000000..6588945
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/.options
@@ -0,0 +1,7 @@
+# Debugging options for the org.eclipse.equinox.security plugin
+
+# Turn on general debugging for the org.eclipse.equinox.security plugin
+org.eclipse.equinox.security/debug=false
+
+# Debug login framework
+org.eclipse.equinox.security/debug/loginFramework=false
diff --git a/bundles/org.eclipse.equinox.security/.project b/bundles/org.eclipse.equinox.security/.project
new file mode 100644
index 0000000..b44b241
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/.project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.equinox.security</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.ibm.sse.model.structuredbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.equinox.security/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.security/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..1bce9db
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,331 @@
+#Tue Jan 29 15:26:50 EST 2008
+eclipse.preferences.version=1
+instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=1000
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=error
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.3
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=false
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false
+org.eclipse.jdt.core.formatter.comment.format_line_comments=false
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=800
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
diff --git a/bundles/org.eclipse.equinox.security/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.equinox.security/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..416d090
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,59 @@
+#Tue Sep 18 13:56:07 EDT 2007
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_core
+formatter_settings_version=11
+instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=;
+org.eclipse.jdt.ui.ondemandthreshold=3
+org.eclipse.jdt.ui.staticondemandthreshold=99
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_variable_declarations_final=true
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=false
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/bundles/org.eclipse.equinox.security/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.equinox.security/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 0000000..bc8d37e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,3 @@
+#Thu Sep 13 15:23:29 EDT 2007
+eclipse.preferences.version=1
+resolve.requirebundle=false
diff --git a/bundles/org.eclipse.equinox.security/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.security/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..18057a7
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/META-INF/MANIFEST.MF
@@ -0,0 +1,31 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.equinox.security;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Bundle-Activator: org.eclipse.equinox.internal.security.auth.AuthPlugin
+Export-Package: org.eclipse.equinox.internal.security.auth;x-internal:=true,
+ org.eclipse.equinox.internal.security.auth.events;x-internal:=true,
+ org.eclipse.equinox.internal.security.auth.ext.loader;x-internal:=true,
+ org.eclipse.equinox.internal.security.auth.nls;x-internal:=true,
+ org.eclipse.equinox.internal.security.credentials;x-internal:=true,
+ org.eclipse.equinox.internal.security.storage;x-internal:=true,
+ org.eclipse.equinox.security.auth,
+ org.eclipse.equinox.security.auth.credentials,
+ org.eclipse.equinox.security.auth.event,
+ org.eclipse.equinox.security.auth.module,
+ org.eclipse.equinox.security.storage,
+ org.eclipse.equinox.security.storage.provider
+Import-Package: org.eclipse.core.runtime,
+ org.eclipse.core.runtime.preferences,
+ org.eclipse.osgi.service.datalocation;version="1.0.0",
+ org.eclipse.osgi.service.debug;version="1.0.0",
+ org.eclipse.osgi.util;version="1.1.0",
+ org.osgi.framework;version="1.4.0",
+ org.osgi.service.prefs;version="1.1.0",
+ org.osgi.util.tracker;version="1.3.3"
+Bundle-RequiredExecutionEnvironment: J2SE-1.4,
+ J2SE-1.5
+Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.equinox.security/about.html b/bundles/org.eclipse.equinox.security/about.html
new file mode 100644
index 0000000..4602330
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 2, 2006</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.security/build.properties b/bundles/org.eclipse.equinox.security/build.properties
new file mode 100644
index 0000000..80423d3
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/build.properties
@@ -0,0 +1,28 @@
+###############################################################################
+# Copyright (c) 2005, 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+bin.includes = plugin.xml,\
+ .,\
+ META-INF/,\
+ schema/,\
+ plugin.properties,\
+ about.html,\
+ .options
+jars.compile.order = .
+source.. = src/
+output.. = bin/
+src.includes = .classpath,\
+ .project,\
+ META-INF/,\
+ build.properties,\
+ plugin.xml,\
+ schema/,\
+ src/,\
+ about.html
diff --git a/bundles/org.eclipse.equinox.security/plugin.properties b/bundles/org.eclipse.equinox.security/plugin.properties
new file mode 100644
index 0000000..86e7d70
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/plugin.properties
@@ -0,0 +1,20 @@
+###############################################################################
+# Copyright (c) 2005, 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+
+pluginName = Equinox Java Authentication and Authorization Service (JAAS)
+providerName = Eclipse.org
+configProviderExtName = JAAS Login Configuration Provider
+loginModuleExtName = JAAS LoginModule
+callbackHandlerExtName = JAAS CallbackHandler
+callbackMappingExtName = JAAS Callback Handler Mapping
+storageLoginConfiguration = Default secure storage configuration provider
+storageManualLogin = Ask user Login Module
+secureStorageName = Secure storage password providers
diff --git a/bundles/org.eclipse.equinox.security/plugin.xml b/bundles/org.eclipse.equinox.security/plugin.xml
new file mode 100644
index 0000000..3edd408
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/plugin.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+
+ <extension-point id="loginConfigurationProvider" name="%configProviderName" schema="schema/loginConfigurationProvider.exsd"/>
+ <extension-point id="loginModule" name="%loginModuleExtName" schema="schema/loginModule.exsd"/>
+ <extension-point id="callbackHandler" name="%callbackHandlerExtName" schema="schema/callbackHandler.exsd"/>
+ <extension-point id="callbackHandlerMapping" name="%callbackMappingExtName" schema="schema/callbackHandlerMapping.exsd"/>
+
+ <extension-point id="secureStorage" name="%secureStorageName" schema="schema/secureStorage.exsd"/>
+
+</plugin>
diff --git a/bundles/org.eclipse.equinox.security/readme.txt b/bundles/org.eclipse.equinox.security/readme.txt
new file mode 100644
index 0000000..88ac4d6
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/readme.txt
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+ *** This is a temporary pre-release container for things we'd like to include in documentation ****
+
+Include a note: If you refer to classes from this bundle by name (such as including
+them in login configuration files), don't forget to add dependency on
+org.eclipse.equinox.security to your bundle.
+
+
diff --git a/bundles/org.eclipse.equinox.security/schema/callbackHandler.exsd b/bundles/org.eclipse.equinox.security/schema/callbackHandler.exsd
new file mode 100644
index 0000000..ba02f18
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/schema/callbackHandler.exsd
@@ -0,0 +1,110 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.equinox.security.auth">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.equinox.security.auth" id="callbackHandler" name="JAAS Callback Handler"/>
+ </appInfo>
+ <documentation>
+ The loginModule extension point provides a way for a bundle to register class implementing CallbackHandler with the Java Authentication and Authorization Service (JAAS). After specifying a Callback Handler using this extension point, the callbackHandlerMapping extension point can be used to set this callbackHander as the default to be used for a given JAAS login configuration.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <complexType>
+ <sequence>
+ <element ref="callbackHandler"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+ A unique id for this Callback Handler. This id is referenced from a callbackHandlerMapping extension point.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="callbackHandler">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ Describes the class that implements the <tt>javax.security.auth.callback.CallbackHandler</tt> interface.
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn=":javax.security.auth.CallbackHandler"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="since"/>
+ </appInfo>
+ <documentation>
+ _CUTLASS_
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ <pre> <extension id="defaultHttpBasicCallbackHandler"
+ name="Default CallbackHandler for HTTP-BASIC Login Configuration"
+ point="org.eclipse.equinox.security.callbackHandler">
+ <callbackHandler class="org.eclipse.equinox.internal.security.auth.dialog.HttpBasicLoginDialog"/>
+ </extension></pre>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiInfo"/>
+ </appInfo>
+ <documentation>
+ The JAAS API is part of the Java Runtime Environment version 1.4 and above.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ No public Callback Handlers are provided by the platform.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ Copyright (c) 2005, 2007 IBM Corporation and others.<br>
+All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/bundles/org.eclipse.equinox.security/schema/callbackHandlerMapping.exsd b/bundles/org.eclipse.equinox.security/schema/callbackHandlerMapping.exsd
new file mode 100644
index 0000000..e7ae85b
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/schema/callbackHandlerMapping.exsd
@@ -0,0 +1,116 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.equinox.security.auth">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.equinox.security.auth" id="callbackHandlerMapping" name="JAAS Callback Handler Mapping"/>
+ </appInfo>
+ <documentation>
+ Maps a callback handler to a JAAS login configuration. The platform will automatically provide the specified callback handler to the JAAS login modules defined by the login configuration.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <complexType>
+ <sequence>
+ <element ref="callbackHandlerMapping"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="callbackHandlerMapping">
+ <complexType>
+ <attribute name="configName" type="string" use="required">
+ <annotation>
+ <documentation>
+ The name of the JAAS login configuration that will use this callbackHandler.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="callbackHandlerId" type="string" use="required">
+ <annotation>
+ <documentation>
+ The id of the callbackHandlers extension that defines the callback hander class.
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="since"/>
+ </appInfo>
+ <documentation>
+ _CUTLASS_
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ <pre> <extension
+ name="HTTP CallbackHandler Mapping"
+ point="org.eclipse.equinox.security.callbackHandlerMapping">
+ <callbackHandlerMapping
+ callbackHandlerId="org.eclipse.equinox.security.ui.defaultHttpBasicCallbackHandler"
+ configName="HTTP"/>
+ </extension></pre>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiInfo"/>
+ </appInfo>
+ <documentation>
+
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ Copyright (c) 2005, 2007 IBM Corporation and others.<br>
+All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/bundles/org.eclipse.equinox.security/schema/loginConfigurationProvider.exsd b/bundles/org.eclipse.equinox.security/schema/loginConfigurationProvider.exsd
new file mode 100644
index 0000000..8cfeab9
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/schema/loginConfigurationProvider.exsd
@@ -0,0 +1,120 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.equinox.security.auth">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.equinox.security.auth" id="loginConfigurationProvider" name="Login Configuration Provider"/>
+ </appInfo>
+ <documentation>
+ A login configuration provider is a class that takes a login configuration name and returns a list of login modules that make up that login configuration, including various properties associated with that login module. The configuration provider must extend the javax.security.auth.login.Configuration class and implement the getAppConfigurationEntry() method.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <documentation>
+ The extension point descriptor.
+ </documentation>
+ </annotation>
+ <complexType>
+ <sequence minOccurs="1" maxOccurs="unbounded">
+ <element ref="loginConfigurationProvider"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="loginConfigurationProvider">
+ <annotation>
+ <documentation>
+ An entry describing a particular Configuration provider from which to load named login configurations. By default, the platform supports loginmodules provided via extension points. See the definition for org.eclipse.equinox.security.loginConfiguration for more information.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ The class of the login Configuration, which must be a subclass of <tt>javax.security.auth.login.Configuration</tt>.
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn="javax.security.auth.login.Configuration"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="since"/>
+ </appInfo>
+ <documentation>
+ _CUTLASS_
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ <pre> <extension
+ id="accountLoginConfigurationProvider"
+ point="org.eclipse.equinox.security.loginConfigurationProvider">
+ <loginConfigurationProvider class="org.eclipse.equinox.accounts.internal.AccountsLoginConfigProvider"/>
+ </extension></pre>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiInfo"/>
+ </appInfo>
+ <documentation>
+ The JAAS API is part of the Java Runtime Environment version 1.4 and above.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ No public login configuration providers are included in the platform.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ Copyright (c) 2005, 2007 IBM Corporation and others.<br>
+All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/bundles/org.eclipse.equinox.security/schema/loginModule.exsd b/bundles/org.eclipse.equinox.security/schema/loginModule.exsd
new file mode 100644
index 0000000..cdb2a52
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/schema/loginModule.exsd
@@ -0,0 +1,133 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.equinox.security.auth">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.equinox.security.auth" id="loginModule" name="JAAS Login Module"/>
+ </appInfo>
+ <documentation>
+ The loginModule extension point provides a way for a bundle to register class implementing LoginModule with the Java Authentication and Authorization Service (JAAS).
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <documentation>
+ The extension point descriptor.
+ </documentation>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="loginModule"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="loginModule">
+ <annotation>
+ <documentation>
+ An entry defining a single LoginModule that can be used for authenticating users. See
+<A HREF="http://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/spi/LoginModule.html">javax.security.auth.spi.LoginModule</A> for more information.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ The fully qualified name of a class which implements the LoginModule provider interface, <tt>javax.security.auth.login.spi.LoginModule</tt>.
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn=":javax.security.auth.spi.LoginModule"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ <attribute name="description" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="since"/>
+ </appInfo>
+ <documentation>
+ _CUTLASS_
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ <pre> <extension
+ id="httpBasicLoginModule"
+ name="httpBasicLoginModule"
+ point="org.eclipse.equinox.security.loginModule">
+ <loginModule class="org.eclipse.equinox.accounts.internal.auth.module.HttpBasicLoginModule"
+description="org.eclipse.equinox.accounts.internal.auth.module.HttpBasicLoginModule"/>
+ </extension></pre>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiInfo"/>
+ </appInfo>
+ <documentation>
+ The JAAS API is part of the Java Runtime Environment version 1.4 and above.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ No public login modules are provided by the platform.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ Copyright (c) 2005, 2007 IBM Corporation and others.<br>
+All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/bundles/org.eclipse.equinox.security/schema/secureStorage.exsd b/bundles/org.eclipse.equinox.security/schema/secureStorage.exsd
new file mode 100644
index 0000000..242ebfa
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/schema/secureStorage.exsd
@@ -0,0 +1,114 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.equinox.security.auth" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.equinox.security.auth" id="secureStorage" name="Secure strorage modules"/>
+ </appinfo>
+ <documentation>
+ Describes implementation of the Equinox secure storage module.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <complexType>
+ <sequence>
+ <element ref="provider"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="provider">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ Class implementing password provider interface.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn="org.eclipse.equinox.security.storage.provider.PasswordProvider:"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="priority" type="string" use="required">
+ <annotation>
+ <documentation>
+ The integer number 0 to 10 describing priority of this password provider, with 0 being the lowest priority. Newly created secure preferences will use the password provider with the highest priority. If multiple providers have the same priority, an arbitrary provider among them will be selected.
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ [Enter the first release in which this extension point appears.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiInfo"/>
+ </appinfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+
+ <annotation>
+ <appinfo>
+ <meta.section type="implementation"/>
+ </appinfo>
+ <documentation>
+ [Enter information about supplied implementation of this extension point.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2008 IBM Corporation and others.<br>
+All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/AuthPlugin.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/AuthPlugin.java
new file mode 100644
index 0000000..abe6517
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/AuthPlugin.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.auth;
+
+import java.net.URL;
+import org.eclipse.core.runtime.*;
+import org.eclipse.equinox.internal.security.storage.PasswordProviderSelector;
+import org.eclipse.equinox.internal.security.storage.SecurePreferencesMapper;
+import org.eclipse.osgi.service.datalocation.Location;
+import org.eclipse.osgi.service.debug.DebugOptions;
+import org.osgi.framework.*;
+import org.osgi.util.tracker.ServiceTracker;
+
+// XXX general comment: how this bundle reacts to dynamic events (registry, OSGi) ?
+
+public class AuthPlugin implements BundleActivator {
+
+ /**
+ * The unique identifier constant of this plug-in.
+ */
+ public static final String PI_AUTH = "org.eclipse.equinox.security"; //$NON-NLS-1$
+
+ private static AuthPlugin singleton;
+
+ private BundleContext bundleContext;
+ private ServiceTracker debugTracker = null;
+ private ServiceTracker configTracker = null;
+
+ public static boolean DEBUG = false;
+ public static boolean DEBUG_LOGIN_FRAMEWORK = false;
+
+ /*
+ * Returns the singleton for this Activator. Callers should be aware that
+ * this will return null if the bundle is not active.
+ */
+ public static AuthPlugin getDefault() {
+ return singleton;
+ }
+
+ public AuthPlugin() {
+ super();
+ }
+
+ public void start(BundleContext context) throws Exception {
+ bundleContext = context;
+ singleton = this;
+
+ DEBUG = getBooleanOption(PI_AUTH + "/debug", false); //$NON-NLS-1$
+ if (DEBUG)
+ DEBUG_LOGIN_FRAMEWORK = getBooleanOption(PI_AUTH + "/debug/loginFramework", false); //$NON-NLS-1$
+
+ // SecurePlatformInternal is started lazily when first SecureContext is created (this reduces
+ // time spend in the bundle activator).
+ }
+
+ public void stop(BundleContext context) throws Exception {
+
+ PasswordProviderSelector.getInstance().stop();
+ SecurePreferencesMapper.stop();
+ SecurePlatformInternal.getInstance().stop();
+
+ if (debugTracker != null) {
+ debugTracker.close();
+ debugTracker = null;
+ }
+ if (configTracker != null) {
+ configTracker.close();
+ configTracker = null;
+ }
+ bundleContext = null;
+ singleton = null;
+ }
+
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public void logError(String msg, Throwable e) {
+ if (bundleContext == null) {
+ System.err.println(msg);
+ if (e != null)
+ e.printStackTrace(System.err);
+ } else {
+ ILog log = Platform.getLog(bundleContext.getBundle());
+ log.log(new Status(IStatus.ERROR, PI_AUTH, msg, e));
+ }
+ }
+
+ public void logMessage(String msg) {
+ if (bundleContext == null) {
+ System.out.println(msg);
+ } else {
+ ILog log = Platform.getLog(bundleContext.getBundle());
+ log.log(new Status(IStatus.INFO, PI_AUTH, msg, null));
+ }
+ }
+
+ public boolean getBooleanOption(String option, boolean defaultValue) {
+ if (debugTracker == null) {
+ if (bundleContext == null)
+ return defaultValue;
+ debugTracker = new ServiceTracker(bundleContext, DebugOptions.class.getName(), null);
+ debugTracker.open();
+ }
+ DebugOptions options = (DebugOptions) debugTracker.getService();
+ if (options == null)
+ return defaultValue;
+ String value = options.getOption(option);
+ if (value == null)
+ return defaultValue;
+ return value.equalsIgnoreCase("true"); //$NON-NLS-1$
+ }
+
+ public URL getConfigURL() {
+ Filter filter = null;
+ if (configTracker == null) {
+ try {
+ filter = bundleContext.createFilter(Location.CONFIGURATION_FILTER);
+ } catch (InvalidSyntaxException e) {
+ // should never happen
+ }
+ configTracker = new ServiceTracker(bundleContext, filter, null);
+ configTracker.open();
+ }
+ Location location = (Location) configTracker.getService();
+ if (location == null)
+ return null;
+ return location.getURL();
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ConfigurationFactory.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ConfigurationFactory.java
new file mode 100644
index 0000000..c3b9342
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ConfigurationFactory.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.auth;
+
+import java.util.ArrayList;
+import javax.security.auth.login.Configuration;
+import org.eclipse.core.runtime.*;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.osgi.util.NLS;
+
+// TODO is this class expected to read extension registry only once?
+// consider caching/dynamic registry. This should implement registry listener
+// and react to registry events.
+
+// TODO this class creates ConfigurationProvider's from the registry information
+// consider moving it into loader package and renaming to reflect this. (This is not
+// a factory in the general meaning of the pattern.)
+public class ConfigurationFactory {
+
+ final private static String ELEM_PROVIDER = "loginConfigurationProvider";//$NON-NLS-1$
+ final private static String ATTR_PROVIDER_CLASS = "class";//$NON-NLS-1$
+ final private static String POINT_PROVIDER = "org.eclipse.equinox.security.loginConfigurationProvider"; //$NON-NLS-1$
+
+ private static ConfigurationFactory s_instance = new ConfigurationFactory();
+
+ static ConfigurationFactory getInstance() {
+ return s_instance;
+ }
+
+ public Configuration[] getConfigurations() {
+ IExtensionRegistry registry = RegistryFactory.getRegistry();
+ IExtensionPoint point = registry.getExtensionPoint(POINT_PROVIDER);
+ IExtension[] extensions = point.getExtensions();
+
+ ArrayList returnValue = new ArrayList(extensions.length);
+ for (int i = 0; i < extensions.length; i++) {
+ IConfigurationElement[] elements = extensions[i].getConfigurationElements();
+ for (int j = 0; j < elements.length; j++) {
+ Configuration provider = readProvider(elements[j]);
+ if (provider != null)
+ returnValue.add(provider);
+ }
+ }
+ return (Configuration[]) returnValue.toArray(new Configuration[] {});
+ }
+
+ private Configuration readProvider(IConfigurationElement element) {
+ if (!ELEM_PROVIDER.equals(element.getName())) {
+ reportError(SecAuthMessages.unexpectedConfigElement, element.getName(), element, null);
+ return null;
+ }
+ try {
+ return (Configuration) element.createExecutableExtension(ATTR_PROVIDER_CLASS);
+ } catch (CoreException e) {
+ reportError(SecAuthMessages.instantiationFailed, element.getAttribute(ATTR_PROVIDER_CLASS), element, e);
+ return null;
+ }
+ }
+
+ private void reportError(String template, String arg, IConfigurationElement element, Throwable e) {
+ String supplier = element.getContributor().getName();
+ String message = NLS.bind(template, arg, supplier);
+ AuthPlugin.getDefault().logError(message, e);
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ConfigurationFederator.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ConfigurationFederator.java
new file mode 100644
index 0000000..d1bae6c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ConfigurationFederator.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.auth;
+
+import java.util.Hashtable;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.osgi.util.NLS;
+
+public class ConfigurationFederator extends Configuration {
+
+ // TODO this usage needs to be changed. We should retrieve federatedConfigs
+ // from the "ConfigurationFactory" every time we are asked; the "ConfigurationFactory"
+ // shoudl keep a cache that corresponds to what's in the registry and update it on registry
+ // events
+ private Configuration[] federatedConfigs = null;
+
+ private Hashtable configCache = new Hashtable(5);
+ private Hashtable configToProviderMap = new Hashtable(5);
+
+ final private Configuration defaultConfiguration;
+
+ public ConfigurationFederator(Configuration defaultConfiguration) {
+ this.defaultConfiguration = defaultConfiguration;
+ }
+
+ public synchronized AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ AppConfigurationEntry[] returnValue = (AppConfigurationEntry[]) configCache.get(name);
+ if (returnValue != null)
+ return returnValue;
+
+ // Note: adding default config provider last; extension-point based configs are queried first
+ Configuration[] configs = getFederatedConfigs();
+ Configuration[] allConfigs = configs;
+ if (defaultConfiguration != null) {
+ allConfigs = new Configuration[configs.length + 1];
+ System.arraycopy(configs, 0, allConfigs, 0, configs.length);
+ allConfigs[configs.length] = defaultConfiguration;
+ }
+ for (int i = 0; i < allConfigs.length; i++) {
+ boolean found = false;
+ AppConfigurationEntry[] config = allConfigs[i].getAppConfigurationEntry(name);
+ if (config == null)
+ continue;
+ String cachedProviderName = (String) configToProviderMap.get(name);
+ if (cachedProviderName != null && !cachedProviderName.equals(allConfigs[i].getClass().getName())) {
+ String message = NLS.bind(SecAuthMessages.duplicateJaasConfig1, name, cachedProviderName);
+ AuthPlugin.getDefault().logError(message, null);
+ } else {
+ if (found) {
+ String message = NLS.bind(SecAuthMessages.duplicateJaasConfig2, name, cachedProviderName);
+ AuthPlugin.getDefault().logError(message, null);
+ } else if ((config != null) && (config.length != 0)) {
+ returnValue = config;
+ configToProviderMap.put(name, allConfigs[i].getClass().getName());
+ configCache.put(name, returnValue);
+ found = true;
+ }
+ }
+ }
+
+ if (returnValue == null || returnValue.length == 0) {
+ String message = NLS.bind(SecAuthMessages.nonExistantJaasConfig, name);
+ AuthPlugin.getDefault().logError(message, null);
+ }
+ return returnValue;
+ }
+
+ public synchronized void refresh() {
+ for (int i = 0; i < federatedConfigs.length; i++)
+ federatedConfigs[i].refresh();
+ if (defaultConfiguration != null)
+ defaultConfiguration.refresh();
+
+ configCache.clear();
+ configToProviderMap.clear();
+ }
+
+ private Configuration[] getFederatedConfigs() {
+ if (federatedConfigs == null)
+ federatedConfigs = ConfigurationFactory.getInstance().getConfigurations();
+ return federatedConfigs;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/SecureContext.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/SecureContext.java
new file mode 100644
index 0000000..3b60f54
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/SecureContext.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.auth;
+
+import java.net.URL;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import org.eclipse.equinox.internal.security.auth.events.SecurityEventsManager;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.equinox.security.auth.ISecureContext;
+import org.eclipse.equinox.security.auth.event.ISecurityListener;
+
+public class SecureContext implements ISecureContext {
+
+ private String configName;
+ private LoginContext loginContext;
+ private CallbackHandler handler;
+
+ private SecurityEventsManager eventsManager = new SecurityEventsManager();
+ private boolean loggedIn = false;
+
+ public SecureContext(String configugationName) {
+ this(configugationName, null, null);
+ }
+
+ public SecureContext(String configugationName, URL configFile, CallbackHandler handler) {
+ configName = configugationName;
+ SecurePlatformInternal platform = SecurePlatformInternal.getInstance();
+ if (configFile != null)
+ platform.addConfigURL(configFile); // this call MUST be done before start()
+ platform.start();
+ this.handler = handler;
+ }
+
+ public void login() throws LoginException {
+ LoginContext context = getLoginContext();
+ LoginException loginException = null;
+ eventsManager.notifyLoginBegin(context.getSubject());
+ try {
+ context.login();
+ } catch (LoginException e) {
+ loginException = e;
+ }
+ // subject might have changed if login() was triggered
+ eventsManager.notifyLoginEnd(context.getSubject(), loginException);
+ if (loginException != null) {
+ LoginException rtvException = new LoginException(SecAuthMessages.loginFailure);
+ rtvException.initCause(loginException);
+ throw rtvException;
+ }
+ loggedIn = true;
+ }
+
+ public void logout() throws LoginException {
+ LoginContext context = getLoginContext();
+ Subject subject = getLoginContext().getSubject();
+ eventsManager.notifyLogoutBegin(subject);
+
+ LoginException loginException = null;
+ try {
+ context.logout();
+ } catch (LoginException e) {
+ loginException = e;
+ }
+ eventsManager.notifyLogoutEnd(subject, loginException);
+ loggedIn = false;
+ }
+
+ public Subject getSubject() throws LoginException {
+ if (!loggedIn)
+ login();
+ return getLoginContext().getSubject();
+ }
+
+ private LoginContext getLoginContext() throws LoginException {
+ if (loginContext != null)
+ return loginContext;
+
+ CallbackHandler callbackHandler;
+ if (handler == null)
+ callbackHandler = SecurePlatformInternal.getInstance().loadCallbackHandler(configName);
+ else
+ callbackHandler = handler;
+
+ if (callbackHandler == null)
+ loginContext = new LoginContext(configName);
+ else
+ loginContext = new LoginContext(configName, callbackHandler);
+ return loginContext;
+ }
+
+ public void registerListener(ISecurityListener listener) {
+ eventsManager.addListener(listener);
+ }
+
+ public void unregisterListener(ISecurityListener listener) {
+ eventsManager.removeListener(listener);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/SecurePlatformInternal.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/SecurePlatformInternal.java
new file mode 100644
index 0000000..215588b
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/SecurePlatformInternal.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.auth;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.Security;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.Configuration;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.equinox.internal.security.auth.ext.loader.ExtCallbackHandlerLoader;
+
+// TBD what happens for server-side implementations if configurations are shared across all processes on VM?
+
+public class SecurePlatformInternal {
+
+ private static final String PROVIDER_URL_BASE = "login.config.url.";//$NON-NLS-1$
+ private static final int MAX_PROVIDER_URL_COUNT = 777; // arbitrary upper limit on the number of provider URLs
+ private Configuration defaultConfiguration;
+ private ExtCallbackHandlerLoader callbackHandlerLoader = new ExtCallbackHandlerLoader();
+
+ private boolean running = false;
+ private static final SecurePlatformInternal s_instance = new SecurePlatformInternal();
+
+ private SecurePlatformInternal() {
+ // hides default constructor
+ }
+
+ public static final SecurePlatformInternal getInstance() {
+ return s_instance;
+ }
+
+ public CallbackHandler loadCallbackHandler(String configurationName) {
+ return callbackHandlerLoader.loadCallbackHandler(configurationName);
+ }
+
+ /**
+ * Java docs specify that if multiple config files are passed in, they will be merged into one file.
+ * Hence, aside from implementation details, no priority information is specified by the order
+ * of config files. In this implementation we add customer's config file to the end of the list.
+ *
+ * This method substitutes default login configuration:
+ * Configuration Inquiries -> ConfigurationFederator ->
+ * 1) Extension Point supplied config providers;
+ * 2) default Java config provider ("login.configuration.provider")
+ */
+ public void start() {
+ if (running)
+ return;
+ try {
+ defaultConfiguration = Configuration.getConfiguration();
+ } catch (SecurityException e) {
+ // could be caused by missing configuration provider URL;
+ // this might be OK if default config provider is ignored
+ defaultConfiguration = null;
+ }
+ Configuration.setConfiguration(new ConfigurationFederator(defaultConfiguration));
+ running = true;
+ }
+
+ public void stop() {
+ if (!running)
+ return;
+ Configuration.setConfiguration(defaultConfiguration);
+ defaultConfiguration = null;
+ running = false;
+ }
+
+ public boolean addConfigURL(URL url) {
+ if (url == null)
+ return false;
+
+ // stop on a first empty URL entry - we will use it to add our new element
+ for (int i = 1; i <= MAX_PROVIDER_URL_COUNT; i++) {
+ String tag = PROVIDER_URL_BASE + Integer.toString(i);
+ String currentURL = Security.getProperty(tag);
+ if (currentURL != null && currentURL.length() != 0)
+ continue;
+ String path;
+ try {
+ // in case URL is contained in a JARed bundle, this will extract it into a file system
+ path = FileLocator.toFileURL(url).toExternalForm();
+ } catch (IOException e) {
+ path = url.toExternalForm();
+ }
+ Security.setProperty(tag, path);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/events/SecurityEventsManager.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/events/SecurityEventsManager.java
new file mode 100644
index 0000000..2280935
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/events/SecurityEventsManager.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.auth.events;
+
+import java.util.Iterator;
+import java.util.Vector;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+import org.eclipse.equinox.security.auth.event.*;
+
+public class SecurityEventsManager {
+
+ private Vector listeners = new Vector(5);
+
+ synchronized public void addListener(ISecurityListener listener) {
+ listeners.add(listener);
+ }
+
+ synchronized public void removeListener(ISecurityListener listener) {
+ listeners.remove(listener);
+ }
+
+ public void notifyLoginBegin(Subject subject) {
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ Object listener = i.next();
+ if (listener instanceof ILoginListener)
+ ((ILoginListener) listener).onLoginStart(subject);
+ }
+ }
+
+ public void notifyLoginEnd(Subject subject, LoginException loginException) {
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ Object listener = i.next();
+ if (listener instanceof ILoginListener)
+ ((ILoginListener) listener).onLoginFinish(subject, loginException);
+ }
+ }
+
+ public void notifyLogoutBegin(Subject subject) {
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ Object listener = i.next();
+ if (listener instanceof ILogoutListener)
+ ((ILogoutListener) listener).onLogoutStart(subject);
+ }
+ }
+
+ public void notifyLogoutEnd(Subject subject, LoginException loginException) {
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ Object listener = i.next();
+ if (listener instanceof ILogoutListener)
+ ((ILogoutListener) listener).onLogoutFinish(subject, loginException);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ext/loader/ExtCallbackHandlerLoader.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ext/loader/ExtCallbackHandlerLoader.java
new file mode 100644
index 0000000..368836d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ext/loader/ExtCallbackHandlerLoader.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.auth.ext.loader;
+
+import javax.security.auth.callback.CallbackHandler;
+import org.eclipse.core.runtime.*;
+import org.eclipse.equinox.internal.security.auth.AuthPlugin;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.osgi.util.NLS;
+
+// XXX rename: CallbackHandlerLoader
+public class ExtCallbackHandlerLoader {
+
+ final private static String POINT_HANDLER = AuthPlugin.PI_AUTH + "." + "callbackHandler"; //$NON-NLS-1$ //$NON-NLS-2$
+ final private static String ELEM_HANDLER = "callbackHandler"; //$NON-NLS-1$
+ final private static String ATTR_HANDLER_CLASS = "class"; //$NON-NLS-1$
+
+ final private static String POINT_MAPPING = AuthPlugin.PI_AUTH + "." + "callbackHandlerMapping"; //$NON-NLS-1$ //$NON-NLS-2$
+ final private static String ELEM_MAPPING = "callbackHandlerMapping"; //$NON-NLS-1$
+ final private static String ATTR_MAPPING_CONFIGNAME = "configName";//$NON-NLS-1$
+ final private static String ATTR_MAPPING_CALLBACKID = "callbackHandlerId"; //$NON-NLS-1$
+
+ public CallbackHandler loadCallbackHandler(String configName) {
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+
+ // First, map config name -> callback handler ID
+ IExtensionPoint point = registry.getExtensionPoint(POINT_MAPPING);
+ IExtension[] extenders = point.getExtensions();
+ String extensionId = null;
+ for (int i = 0; i < extenders.length; i++) {
+ IConfigurationElement[] confEelements = extenders[i].getConfigurationElements();
+ if (confEelements.length != 1)
+ continue; // TBD error message?
+ extensionId = loadMappingEntry(confEelements[0], configName);
+ if (extensionId != null)
+ break;
+ }
+ if (extensionId == null)
+ return null;
+
+ // Next, load class specified by the callback handler ID
+ IExtensionPoint pointCallbackHandler = registry.getExtensionPoint(POINT_HANDLER);
+ IExtension extension = pointCallbackHandler.getExtension(extensionId);
+ if (extension == null)
+ return null;
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ if (elements.length != 1)
+ return null; // TBD error message?
+ return loadHandlerClass(elements[0]);
+ }
+
+ private String loadMappingEntry(IConfigurationElement element, String configName) {
+ if (!expectedElement(element, ELEM_MAPPING))
+ return null;
+ if (configName.equals(element.getAttribute(ATTR_MAPPING_CONFIGNAME)))
+ return element.getAttribute(ATTR_MAPPING_CALLBACKID);
+ return null;
+ }
+
+ private CallbackHandler loadHandlerClass(IConfigurationElement element) {
+ if (!expectedElement(element, ELEM_HANDLER))
+ return null;
+ try {
+ return (CallbackHandler) element.createExecutableExtension(ATTR_HANDLER_CLASS);
+ } catch (CoreException e) {
+ String message = NLS.bind(SecAuthMessages.instantiationFailed1, element.getAttribute(ATTR_HANDLER_CLASS));
+ AuthPlugin.getDefault().logError(message, e);
+ return null;
+ }
+ }
+
+ private boolean expectedElement(IConfigurationElement element, String expectedName) {
+ if (expectedName.equals(element.getName()))
+ return true;
+ String supplier = element.getContributor().getName();
+ String message = NLS.bind(SecAuthMessages.unexpectedConfigElement, element.getName(), supplier);
+ AuthPlugin.getDefault().logError(message, null);
+ return false;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ext/loader/ExtLoginModuleLoader.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ext/loader/ExtLoginModuleLoader.java
new file mode 100644
index 0000000..9dc04bf
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/ext/loader/ExtLoginModuleLoader.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.auth.ext.loader;
+
+import java.util.Map;
+import javax.security.auth.spi.LoginModule;
+import org.eclipse.core.runtime.*;
+import org.eclipse.equinox.internal.security.auth.AuthPlugin;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.equinox.security.auth.module.ExtensionLoginModule;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Expected usage pattern: this method is called infrequently (a few times per life cycle;
+ * most likely once). As such, no internal caches are maintained and it simply goes
+ * to the registry and retrieves information when asked.
+ */
+public class ExtLoginModuleLoader {
+
+ final private static String POINT_MODULE = AuthPlugin.PI_AUTH + "." + "loginModule"; //$NON-NLS-1$ //$NON-NLS-2$
+ final private static String ELEM_MODULE = "loginModule"; //$NON-NLS-1$
+ final private static String ATTR_MODULE_CLASS = "class"; //$NON-NLS-1$
+
+ public static LoginModule load(Map options) {
+ IExtensionRegistry registry = Platform.getExtensionRegistry();
+ IExtensionPoint point = registry.getExtensionPoint(POINT_MODULE);
+ IExtension[] extensions = point.getExtensions();
+
+ String targetPoint = (String) options.get(ExtensionLoginModule.OPTION_MODULE_POINT);
+
+ LoginModule loginModule = null;
+ for (int i = 0; i < extensions.length; i++) {
+ String sourcePoint = extensions[i].getUniqueIdentifier();
+ if (sourcePoint == null) // technically, IDs on extensions are optional
+ continue;
+ if (sourcePoint.equals(targetPoint)) {
+ IConfigurationElement[] elements = extensions[i].getConfigurationElements();
+ int elementCount = elements.length;
+ if (elementCount == 1)
+ loginModule = readEntry(elements[0]);
+ else {
+ String message = NLS.bind(SecAuthMessages.invalidLoginmoduleCount, Integer.toString(elementCount));
+ AuthPlugin.getDefault().logError(message, null);
+ }
+ }
+ }
+ return loginModule;
+ }
+
+ private static LoginModule readEntry(IConfigurationElement element) {
+ // XXX make this check an utility
+ if (!ELEM_MODULE.equals(element.getName())) {
+ String supplier = element.getContributor().getName();
+ String message = NLS.bind(SecAuthMessages.unexpectedConfigElement, element.getName(), supplier);
+ AuthPlugin.getDefault().logError(message, null);
+ return null;
+ }
+
+ // XXX make creation of executable extension and its error handling an utility
+ try {
+ LoginModule module = (LoginModule) element.createExecutableExtension(ATTR_MODULE_CLASS);
+ return module;
+ // future expandability: description is stored in the attribute "description"
+ } catch (CoreException e) {
+ String supplier = element.getContributor().getName();
+ String message = NLS.bind(SecAuthMessages.instantiationFailed, element.getAttribute(ATTR_MODULE_CLASS), supplier);
+ AuthPlugin.getDefault().logError(message, e);
+ return null;
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/nls/SecAuthMessages.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/nls/SecAuthMessages.java
new file mode 100644
index 0000000..47f8b8c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/nls/SecAuthMessages.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.auth.nls;
+
+import org.eclipse.osgi.util.NLS;
+
+public class SecAuthMessages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.equinox.internal.security.auth.nls.messages"; //$NON-NLS-1$
+
+ // General use
+ public static String instantiationFailed;
+ public static String instantiationFailed1;
+ public static String nullArguments;
+ public static String noCallbackhandlerService;
+ public static String badServicelistenerSyntaxString;
+ public static String serviceAlreadyInstalled;
+ public static String loginadminServiceNotIntstalled;
+ public static String elementUnexpected;
+ public static String loginFailure;
+ public static String startFirst;
+ public static String stopFirst;
+
+ // Configuration provider
+ public static String unexpectedConfigElement;
+ public static String invalidConfigURL;
+ public static String badProviderUrl;
+ public static String providerUrlUnspecified;
+
+ // Configuration aggregator
+ public static String nonExistantJaasConfig;
+ public static String duplicateJaasConfig1;
+ public static String duplicateJaasConfig2;
+
+ // Configuration loaders
+ public static String invalidControlFlag;
+ public static String configurationEntryInvalid;
+ public static String configurationEntryTypeUnknown;
+ public static String documentSystemIdInvalid;
+ public static String configurationEntryDuplicate;
+ public static String invalidDocument;
+ public static String documentExceptionIO;
+ public static String documentExceptionParsing;
+ public static String configurationDuplicate;
+
+ // LoginModule loader
+ public static String invalidLoginmoduleCount;
+
+ // LoginModule proxy
+ public static String loginmoduleFactoryNotSet;
+ public static String loginmoduleFactoryAlreadySet;
+ public static String unsetLoginmoduleFactoryError;
+
+ // Secure storage
+ public static String loginFileURL;
+ public static String loginNoPassword;
+ public static String loginNoDefaultLocation;
+ public static String handleIncorrectFormat;
+ public static String noDigestAlgorithm;
+ public static String noSecureStorageModule;
+ public static String noSecureStorageModules;
+ public static String entryTypeIsNull;
+ public static String entryTypeInvalid;
+ public static String qualifierInvalid;
+ public static String qualifierIsNull;
+ public static String removedNode;
+ public static String invalidNodePath;
+ public static String errorOnSave;
+ public static String keyringNotAvailable;
+ public static String noDefaultPassword;
+ public static String invalidEntryFormat;
+ public static String noAlgorithms;
+ public static String noAlgorithm;
+ public static String usingAlgorithm;
+
+ static {
+ // load message values from bundle file
+ reloadMessages();
+ }
+
+ public static void reloadMessages() {
+ NLS.initializeMessages(BUNDLE_NAME, SecAuthMessages.class);
+ }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/nls/messages.properties b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/nls/messages.properties
new file mode 100644
index 0000000..41dd0f9
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/auth/nls/messages.properties
@@ -0,0 +1,75 @@
+###############################################################################
+# Copyright (c) 2005, 2008 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+
+## General use
+instantiationFailed = Unexpected exception when instantiating class \"{0}\" specified by \"{1}\".
+instantiationFailed1 = Unexpected exception when instantiating class \"{0}\".
+nullArguments = Arguments cannot be null.
+noCallbackhandlerService =An ICallbackHandlerService is not installed.
+badServicelistenerSyntaxString = Syntax of ServiceListener String is invalid.
+serviceAlreadyInstalled = Service is already installed.
+loginadminServiceNotIntstalled = An ILoginAdminService is not installed.
+elementUnexpected = Specified IConfigurationElement is not of type \"{0}\".
+loginFailure = Failed to log in.
+startFirst = Secure platform is not running. Make sure that secure platform is started.
+stopFirst = Secure platform is already running. Make sure that secure platform is stopped first.
+
+## Configuration provider
+invalidConfigURL = Invalid URL \"{0}\" specified by \"{1}\" for Configuration provider.
+unexpectedConfigElement = Unexpected element \"{0}\" specified by \"{1}\" for Configuration provider.
+badProviderUrl = MalformedURLException thrown when parsing provider URL.
+providerUrlUnspecified = No provider URLs specified for current provider.
+
+## Configuration aggregator
+nonExistantJaasConfig = Could not locate JAAS Configuration with name \"{0}\", verify that the configuration exists and is non-empty.
+duplicateJaasConfig1 = A JAAS Configuration named \"{0}\" is already provided by Provider \"{1}\".
+duplicateJaasConfig2 = Duplicate Configuration named \"{0}\" found in Provider \"{1}\".
+
+## Configuration loaders
+invalidControlFlag = LoginModuleControlFlag \"{0}\" is not valid.
+configurationEntryInvalid = Configuration Entry \"{0}\" is not valid, check \"{1}\" and \"{2}\" values.
+configurationEntryTypeUnknown = Type \"{0}\" is not supported by this configuration entry.
+documentSystemIdInvalid = JAAS Configuration document system ID is invalid.
+configurationEntryDuplicate = Duplicate Configuration Entry at index \"{0}\", ignoring.
+invalidDocument = JAAS Configuration document not found or invalid format at \"{0}\".
+documentExceptionIO = IOException reading Configuration document.
+documentExceptionParsing == Exception parsing JAAS Configuration.
+configurationDuplicate = Duplicate Configuration named \"{0}\" found in document \"{1}\".
+
+## LoginModule loader
+invalidLoginmoduleCount = Invalid number of LoginModule elements, expected one but found \"{0}\".
+
+## LoginModule proxy
+loginmoduleFactoryNotSet = LoginModule Factory is not set, LoginModule extensions cannot be located.
+loginmoduleFactoryAlreadySet = LoginModule Factory has already been set.
+unsetLoginmoduleFactoryError = Wrong LoginModule Factory used to unregister the factory.
+
+## Secure storage
+loginFileURL = Expecting a file URL to specify storage location ({0}).
+loginNoPassword = No password provided.
+loginNoDefaultLocation = Unable to determine secure storage location.
+handleIncorrectFormat== Names must not contain the \"%\" character.
+noDigestAlgorithm = SHA-1 Digest not available. Check the Java configuration file java.security.
+noSecureStorageModule = Unable to locate secure storage module ({0}).
+noSecureStorageModules = No secure storage modules found.
+entryTypeIsNull = Entry type can not be null.
+entryTypeInvalid = Entry type \"{0}\" contains invalid characters. Use ASCII characters 32 to 126 excluding forward slash.
+qualifierInvalid = Qualifier can not be null.
+qualifierIsNull = Qualifier \"{0}\" contains invalid characters. Use ASCII characters 32 to 126 excluding forward slash.
+removedNode = Preference node \"{0}\" has been removed.
+invalidNodePath = Node path \"{0}\" is not valid.
+errorOnSave = Unable to save secure preferences.
+keyringNotAvailable = Unable to open default secure storage.
+noDefaultPassword = Unable to decrypt entry encoded with default password as no default password is currently specified.
+invalidEntryFormat = Invalid data format.
+noAlgorithms = No encryption algorithms installed. Unable to access secure storage.
+noAlgorithm = Unable to find provider of the encryption algorithm \"{0}\". Unable to access secure storage.
+usingAlgorithm = Unable to find default encryption algorithm \"{0}\", using \"{1}\" instead.
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/credentials/EquinoxPrivateCredential.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/credentials/EquinoxPrivateCredential.java
new file mode 100644
index 0000000..2a87b83
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/credentials/EquinoxPrivateCredential.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.credentials;
+
+import javax.crypto.spec.PBEKeySpec;
+import org.eclipse.equinox.security.auth.credentials.IPrivateCredential;
+
+public class EquinoxPrivateCredential implements IPrivateCredential {
+
+ final private PBEKeySpec key;
+ final private String loginModuleID;
+
+ public EquinoxPrivateCredential(PBEKeySpec privateKey, String loginModuleID) {
+ this.key = privateKey;
+ this.loginModuleID = loginModuleID;
+ }
+
+ public PBEKeySpec getPrivateKey() {
+ return key;
+ }
+
+ public String getProviderID() {
+ return loginModuleID;
+ }
+
+ public void clear() {
+ if (key != null)
+ key.clearPassword();
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/credentials/EquinoxPublicCredential.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/credentials/EquinoxPublicCredential.java
new file mode 100644
index 0000000..149c019
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/credentials/EquinoxPublicCredential.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.credentials;
+
+import java.security.Principal;
+import org.eclipse.equinox.security.auth.credentials.IPublicCredential;
+
+public class EquinoxPublicCredential implements IPublicCredential {
+
+ final private String name;
+ final private Principal primaryRole;
+ final private Principal[] roles;
+ final private String loginModuleID;
+
+ public EquinoxPublicCredential(String name, Principal primaryRole, String loginModuleID) {
+ this.name = name;
+ this.primaryRole = primaryRole;
+ this.roles = null;
+ this.loginModuleID = loginModuleID;
+ }
+
+ public EquinoxPublicCredential(String name, Principal[] roles, String loginModuleID) {
+ this.name = name;
+ this.primaryRole = null;
+ this.roles = roles;
+ this.loginModuleID = loginModuleID;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Principal getPrimaryRole() {
+ if (primaryRole != null)
+ return primaryRole;
+ if (roles != null && roles.length >= 1)
+ return roles[0];
+ return null;
+ }
+
+ public Principal[] getRoles() {
+ return roles;
+ }
+
+ public String getProviderID() {
+ return loginModuleID;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/Base64.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/Base64.java
new file mode 100644
index 0000000..09bafd6
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/Base64.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+/**
+ * This is an implementation of Base64 encoding allowing byte sequences to be
+ * converted into strings - safe to be stored in basic Java structures.
+ * <p>
+ * This Base64 encoding does not insert end-of-line characters
+ * (but can properly decode strings with EOLs inserted).
+ * </p>
+ */
+public class Base64 {
+
+ final static private char[] encodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); //$NON-NLS-1$
+
+ final static private byte BASE64_PADDING = 126;
+ final static private byte BASE64_INVALID = 127;
+
+ static private byte[] decodeTable = null;
+
+ synchronized static private void init() {
+ decodeTable = new byte[256];
+ for (int i = 0; i < 256; i++)
+ decodeTable[i] = BASE64_INVALID;
+
+ for (int i = 0; i < 64; i++)
+ decodeTable[encodeTable[i]] = (byte) i;
+
+ decodeTable['='] = BASE64_PADDING;
+ }
+
+ static private byte decode(char c) {
+ if (c >= 256)
+ throw new IllegalArgumentException();
+ return decodeTable[c];
+ }
+
+ static public byte[] decode(String str) {
+ if (str == null)
+ return null;
+ if (decodeTable == null)
+ init();
+
+ // eliminate all unexpected characters (might have EOLs inserted)
+ char[] source = str.toCharArray();
+ int originalSize = source.length;
+ char[] tmp = new char[originalSize];
+ int count = 0;
+ for (int i = 0; i < originalSize; i++) {
+ if (decode(source[i]) != BASE64_INVALID)
+ tmp[count++] = source[i];
+ }
+ char[] chars = new char[count];
+ System.arraycopy(tmp, 0, chars, 0, count);
+
+ int size = chars.length;
+ byte[] result = new byte[size];
+ int pos = 0;
+ for (int i = 0; i < size; i += 4) {
+ byte group1 = decode(chars[i]);
+ byte group2 = (i + 1 < size) ? decode(chars[i + 1]) : 0;
+ byte group3 = (i + 2 < size) ? decode(chars[i + 2]) : 0;
+ byte group4 = (i + 3 < size) ? decode(chars[i + 3]) : 0;
+
+ result[pos++] = (byte) ((group1 << 2) | (group2 >> 4));
+ if (group3 != BASE64_PADDING)
+ result[pos++] = (byte) (((group2 & 0xF) << 4) | (group3 >> 2));
+ if (group4 != BASE64_PADDING)
+ result[pos++] = (byte) (((group3 & 0x3) << 6) | group4);
+ }
+
+ byte[] output = new byte[pos];
+ System.arraycopy(result, 0, output, 0, pos);
+ return output;
+ }
+
+ static public String encode(byte[] bytes) {
+ if (bytes == null)
+ return null;
+ char[] longResult = new char[bytes.length * 2];
+ int pos = 0;
+ for (int i = 0; i < bytes.length; i += 3) {
+ int byte1 = 0xFF & bytes[i];
+ int byte2 = (i + 1 < bytes.length) ? 0xFF & bytes[i + 1] : 0;
+ int byte3 = (i + 2 < bytes.length) ? 0xFF & bytes[i + 2] : 0;
+
+ int group1 = byte1 >> 2;
+ int group2 = ((byte1 & 0x3) << 4) | (byte2 >> 4);
+ int group3 = ((byte2 & 0xF) << 2) | (byte3 >> 6);
+ int group4 = byte3 & 0x3F;
+
+ longResult[pos++] = encodeTable[group1];
+ longResult[pos++] = encodeTable[group2];
+
+ longResult[pos++] = (i + 1 < bytes.length) ? encodeTable[group3] : '=';
+ longResult[pos++] = (i + 2 < bytes.length) ? encodeTable[group4] : '=';
+ }
+
+ char[] result = new char[pos];
+ System.arraycopy(longResult, 0, result, 0, pos);
+ return new String(result);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/CryptoData.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/CryptoData.java
new file mode 100644
index 0000000..c67681f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/CryptoData.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.equinox.security.storage.StorageException;
+
+public class CryptoData {
+
+ static final private char MODULE_ID_SEPARATOR = '\t'; // must not be a valid Base64 char
+
+ /**
+ * Separates salt from the data; this must not be a valid Base64 character.
+ */
+ static private final char SALT_SEPARATOR = ',';
+
+ final private String moduleID;
+ final private byte[] salt;
+ final private byte[] encryptedData;
+
+ public CryptoData(String moduleID, byte[] salt, byte[] data) {
+ this.moduleID = moduleID;
+ this.salt = salt;
+ this.encryptedData = data;
+ }
+
+ public String getModuleID() {
+ return moduleID;
+ }
+
+ public byte[] getSalt() {
+ return salt;
+ }
+
+ public byte[] getData() {
+ return encryptedData;
+ }
+
+ public CryptoData(String data) throws StorageException {
+ // separate moduleID
+ int pos = data.indexOf(MODULE_ID_SEPARATOR);
+ String encrypted;
+ if (pos == -1) { // invalid data format
+ throw new StorageException(StorageException.DECRYPTION_ERROR, SecAuthMessages.invalidEntryFormat);
+ } else if (pos == 0) {
+ moduleID = null;
+ encrypted = data.substring(1);
+ } else {
+ moduleID = data.substring(0, pos);
+ encrypted = data.substring(pos + 1);
+ }
+
+ // separate salt and data
+ int saltPos = encrypted.indexOf(SALT_SEPARATOR);
+ if (saltPos != -1) {
+ salt = Base64.decode(encrypted.substring(0, saltPos));
+ encryptedData = Base64.decode(encrypted.substring(saltPos + 1));
+ } else { // should not happen unless data is modified but handle it anyway
+ salt = new byte[] {0, 0, 0, 0, 0, 0, 0, 0};
+ encryptedData = Base64.decode(encrypted);
+ }
+ }
+
+ public String toString() {
+ StringBuffer encryptedText = (moduleID == null) ? new StringBuffer() : new StringBuffer(moduleID);
+ encryptedText.append(MODULE_ID_SEPARATOR);
+ if (salt != null)
+ encryptedText.append(Base64.encode(salt));
+ encryptedText.append(SALT_SEPARATOR);
+ if (encryptedData != null)
+ encryptedText.append(Base64.encode(encryptedData));
+ return encryptedText.toString();
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/IStorageConstants.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/IStorageConstants.java
new file mode 100644
index 0000000..f67d006
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/IStorageConstants.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+public interface IStorageConstants {
+
+ /**
+ * Preference describing the default cipher algorithm for secure storage
+ */
+ public String CIPHER_KEY = "org.eclipse.equinox.security.preferences.cipher"; //$NON-NLS-1$
+
+ /**
+ * Preference describing the default key factory algorithm for secure storage
+ */
+ public String KEY_FACTORY_KEY = "org.eclipse.equinox.security.preferences.keyFactory"; //$NON-NLS-1$
+
+ /**
+ * Default cipher algorithm to use in secure storage
+ */
+ public String DEFAULT_CIPHER = "PBEWithMD5AndDES"; //$NON-NLS-1$
+
+ /**
+ * Default key factory algorithm to use in secure storage
+ */
+ public String DEFAULT_KEY_FACTORY = "PBEWithMD5AndDES"; //$NON-NLS-1$
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/JavaEncryption.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/JavaEncryption.java
new file mode 100644
index 0000000..23c0b1c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/JavaEncryption.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.util.*;
+import javax.crypto.*;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+import org.eclipse.core.runtime.preferences.ConfigurationScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.equinox.internal.security.auth.AuthPlugin;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.equinox.security.storage.StorageException;
+import org.eclipse.osgi.util.NLS;
+
+// TBD on the UI side provide handling to change "preferred" algorithm using preferences page.
+// Bonus: Default preferences: after the change offer to re-encrypt or delete old default secure prefs.
+
+/**
+ * Note that algorithm detection skips aliases:
+ * Alg.Alias.Cipher.ABC
+ * only a few aliases are useful and it will be harder to separate human-readable
+ * aliases from internal ones.
+ *
+ */
+public class JavaEncryption {
+
+ private final static String SECRET_KEY_FACTORY = "SecretKeyFactory."; //$NON-NLS-1$
+ private final static String CIPHER = "Cipher."; //$NON-NLS-1$
+
+ private final static String sampleText = "sample text for roundtrip testing"; //$NON-NLS-1$
+ private final static PasswordExt samplePassword = new PasswordExt(new PBEKeySpec("password1".toCharArray()), "abc"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ static private final int SALT_ITERATIONS = 10;
+
+ private String keyFactoryAlgorithm = null;
+ private String cipherAlgorithm = null;
+
+ private boolean initialized = false;
+
+ public JavaEncryption() {
+ // placeholder
+ }
+
+ public String getKeyFactoryAlgorithm() {
+ return keyFactoryAlgorithm;
+ }
+
+ public String getCipherAlgorithm() {
+ return cipherAlgorithm;
+ }
+
+ synchronized public void setAlgorithms(String cipherAlgorithm, String keyFactoryAlgorithm) {
+ this.cipherAlgorithm = cipherAlgorithm;
+ this.keyFactoryAlgorithm = keyFactoryAlgorithm;
+ }
+
+ private void init() throws StorageException {
+ if (initialized)
+ return;
+ initialized = true;
+
+ if (cipherAlgorithm != null && keyFactoryAlgorithm != null) {
+ if (roundtrip(cipherAlgorithm, keyFactoryAlgorithm))
+ return;
+ // this is a bad situation - JVM cipher no longer available. Both log and throw an exception
+ String msg = NLS.bind(SecAuthMessages.noAlgorithm, cipherAlgorithm);
+ StorageException e = new StorageException(StorageException.INTERNAL_ERROR, msg);
+ AuthPlugin.getDefault().logError(msg, e);
+ throw e;
+ }
+ if (cipherAlgorithm == null || keyFactoryAlgorithm == null) {
+ IEclipsePreferences eclipseNode = new ConfigurationScope().getNode(AuthPlugin.PI_AUTH);
+ cipherAlgorithm = eclipseNode.get(IStorageConstants.CIPHER_KEY, IStorageConstants.DEFAULT_CIPHER);
+ keyFactoryAlgorithm = eclipseNode.get(IStorageConstants.KEY_FACTORY_KEY, IStorageConstants.DEFAULT_KEY_FACTORY);
+ }
+ if (roundtrip(cipherAlgorithm, keyFactoryAlgorithm))
+ return;
+ String unavailableCipher = cipherAlgorithm;
+
+ HashMap availableCiphers = detect();
+ if (availableCiphers.size() == 0)
+ throw new StorageException(StorageException.INTERNAL_ERROR, SecAuthMessages.noAlgorithms);
+
+ // use first available
+ cipherAlgorithm = (String) availableCiphers.keySet().iterator().next();
+ keyFactoryAlgorithm = (String) availableCiphers.get(cipherAlgorithm);
+
+ String msg = NLS.bind(SecAuthMessages.usingAlgorithm, unavailableCipher, cipherAlgorithm);
+ AuthPlugin.getDefault().logMessage(msg);
+ }
+
+ synchronized public CryptoData encrypt(PasswordExt passwordExt, byte[] clearText) throws StorageException {
+ init();
+ try {
+ SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(keyFactoryAlgorithm);
+ SecretKey key = keyFactory.generateSecret(passwordExt.getPassword());
+
+ byte[] salt = new byte[8];
+ SecureRandom random = new SecureRandom();
+ random.nextBytes(salt);
+ PBEParameterSpec entropy = new PBEParameterSpec(salt, SALT_ITERATIONS);
+
+ Cipher c = Cipher.getInstance(cipherAlgorithm);
+ c.init(Cipher.ENCRYPT_MODE, key, entropy);
+
+ byte[] result = c.doFinal(clearText);
+ return new CryptoData(passwordExt.getModuleID(), salt, result);
+ } catch (InvalidKeyException e) {
+ handle(e, StorageException.ENCRYPTION_ERROR);
+ return null;
+ } catch (InvalidAlgorithmParameterException e) {
+ handle(e, StorageException.ENCRYPTION_ERROR);
+ return null;
+ } catch (IllegalBlockSizeException e) {
+ handle(e, StorageException.ENCRYPTION_ERROR);
+ return null;
+ } catch (BadPaddingException e) {
+ handle(e, StorageException.ENCRYPTION_ERROR);
+ return null;
+ } catch (InvalidKeySpecException e) {
+ handle(e, StorageException.INTERNAL_ERROR);
+ return null;
+ } catch (NoSuchPaddingException e) {
+ handle(e, StorageException.INTERNAL_ERROR);
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ handle(e, StorageException.INTERNAL_ERROR);
+ return null;
+ }
+ }
+
+ synchronized public byte[] decrypt(PasswordExt passwordExt, CryptoData encryptedData) throws StorageException, IllegalStateException, IllegalBlockSizeException, BadPaddingException {
+ init();
+ try {
+ SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(keyFactoryAlgorithm);
+ SecretKey key = keyFactory.generateSecret(passwordExt.getPassword());
+
+ PBEParameterSpec entropy = new PBEParameterSpec(encryptedData.getSalt(), SALT_ITERATIONS);
+
+ Cipher c = Cipher.getInstance(cipherAlgorithm);
+ c.init(Cipher.DECRYPT_MODE, key, entropy);
+
+ byte[] result = c.doFinal(encryptedData.getData());
+ return result;
+ } catch (InvalidAlgorithmParameterException e) {
+ handle(e, StorageException.INTERNAL_ERROR);
+ return null;
+ } catch (InvalidKeyException e) {
+ handle(e, StorageException.INTERNAL_ERROR);
+ return null;
+ } catch (InvalidKeySpecException e) {
+ handle(e, StorageException.INTERNAL_ERROR);
+ return null;
+ } catch (NoSuchPaddingException e) {
+ handle(e, StorageException.INTERNAL_ERROR);
+ return null;
+ } catch (NoSuchAlgorithmException e) {
+ handle(e, StorageException.INTERNAL_ERROR);
+ return null;
+ }
+ }
+
+ private void handle(Exception e, int internalCode) throws StorageException {
+ if (AuthPlugin.DEBUG_LOGIN_FRAMEWORK)
+ e.printStackTrace();
+ StorageException exception = new StorageException(internalCode, e);
+ throw exception;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ // Algorithm detection
+
+ /**
+ * Result: Map:
+ * <String>cipher -> <String>keyFactory
+ */
+ public HashMap detect() {
+ Set ciphers = findProviders(CIPHER);
+ Set keyFactories = findProviders(SECRET_KEY_FACTORY);
+ HashMap availableCiphers = new HashMap(ciphers.size());
+
+ for (Iterator i = ciphers.iterator(); i.hasNext();) {
+ String cipher = (String) i.next();
+ // check if there is a key factory with the same name
+ if (keyFactories.contains(cipher)) {
+ if (roundtrip(cipher, cipher)) {
+ availableCiphers.put(cipher, cipher);
+ continue;
+ }
+ }
+ for (Iterator j = keyFactories.iterator(); j.hasNext();) {
+ String keyFactory = (String) j.next();
+ if (roundtrip(cipher, keyFactory)) {
+ availableCiphers.put(cipher, keyFactory);
+ continue;
+ }
+ }
+ }
+ return availableCiphers;
+ }
+
+ private Set findProviders(String prefix) {
+ Provider[] providers = Security.getProviders();
+ Set algorithms = new HashSet();
+ int prefixLength = prefix.length();
+ for (int i = 0; i < providers.length; i++) {
+ for (Iterator j = providers[i].entrySet().iterator(); j.hasNext();) {
+ Map.Entry entry = (Map.Entry) j.next();
+ Object key = entry.getKey();
+ if (key == null)
+ continue;
+ if (!(key instanceof String))
+ continue;
+ String value = (String) key;
+ if (value.indexOf(' ') != -1) // skips properties like "[Cipher.ABC SupportedPaddings]"
+ continue;
+ if (value.startsWith(prefix)) {
+ String keyFactory = value.substring(prefixLength);
+ algorithms.add(keyFactory);
+ }
+ }
+ }
+ return algorithms;
+ }
+
+ private boolean roundtrip(String testCipher, String testKeyFactory) {
+ String storedCipherAlgorithm = cipherAlgorithm;
+ String storedKeyAlgorithm = keyFactoryAlgorithm;
+ try {
+ cipherAlgorithm = testCipher;
+ keyFactoryAlgorithm = testKeyFactory;
+ CryptoData encrypted = encrypt(samplePassword, sampleText.getBytes());
+ byte[] roundtripBytes = decrypt(samplePassword, encrypted);
+ String result = new String(roundtripBytes);
+ return sampleText.equals(result);
+ } catch (Exception e) {
+ // internal implementation throws both checked and unchecked
+ // exceptions (without much documentation to go on), so have to use catch-all
+ return false;
+ } finally { // reset back
+ cipherAlgorithm = storedCipherAlgorithm;
+ keyFactoryAlgorithm = storedKeyAlgorithm;
+
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PasswordExt.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PasswordExt.java
new file mode 100644
index 0000000..ec4a019
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PasswordExt.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import javax.crypto.spec.PBEKeySpec;
+
+public class PasswordExt {
+
+ final public PBEKeySpec password;
+
+ final public String moduleID;
+
+ public PasswordExt(PBEKeySpec password, String moduleID) {
+ super();
+ this.moduleID = moduleID;
+ this.password = password;
+ }
+
+ public PBEKeySpec getPassword() {
+ return password;
+ }
+
+ public String getModuleID() {
+ return moduleID;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PasswordProviderModuleExt.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PasswordProviderModuleExt.java
new file mode 100644
index 0000000..1ae8370
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PasswordProviderModuleExt.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import javax.crypto.spec.PBEKeySpec;
+import org.eclipse.equinox.security.storage.provider.IPreferencesContainer;
+import org.eclipse.equinox.security.storage.provider.PasswordProvider;
+
+/**
+ * This class associates password provider module with a unique ID.
+ */
+public class PasswordProviderModuleExt {
+
+ final private PasswordProvider providerModule;
+ final private String moduleID;
+
+ public PasswordProviderModuleExt(PasswordProvider module, String moduleID) {
+ this.providerModule = module;
+ this.moduleID = moduleID;
+ }
+
+ public String getID() {
+ return moduleID;
+ }
+
+ public PBEKeySpec login(IPreferencesContainer container) {
+ return providerModule.login(container);
+ }
+
+ public void logout(IPreferencesContainer container) {
+ providerModule.logout(container);
+ }
+
+ public boolean changePassword(Exception e, IPreferencesContainer controller) {
+ return providerModule.changePassword(e, controller);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PasswordProviderSelector.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PasswordProviderSelector.java
new file mode 100644
index 0000000..46f8a39
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PasswordProviderSelector.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import java.util.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.equinox.internal.security.auth.AuthPlugin;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.equinox.security.storage.StorageException;
+import org.eclipse.equinox.security.storage.provider.PasswordProvider;
+import org.eclipse.osgi.util.NLS;
+
+//XXX add validation on module IDs - AZaz09 and dots, absolutely no tabs
+// XXX reserved name DEFAULT_PASSWORD_ID
+
+/**
+ * Finds appropriate password provider module to use.
+ */
+public class PasswordProviderSelector implements IRegistryEventListener {
+
+ final private static String EXTENSION_POINT = "org.eclipse.equinox.security.secureStorage"; //$NON-NLS-1$
+ final private static String STORAGE_MODULE = "provider";//$NON-NLS-1$
+ final private static String MODULE_PRIORITY = "priority";//$NON-NLS-1$
+ final private static String CLASS_NAME = "class";//$NON-NLS-1$
+
+ private Map modules = new HashMap(5); // cache of modules found
+
+ private class ExtStorageModule {
+ public String moduleID;
+ public IConfigurationElement element;
+ public int priority;
+
+ public ExtStorageModule(String id, IConfigurationElement element, int priority) {
+ super();
+ this.element = element;
+ this.moduleID = id;
+ this.priority = priority;
+ }
+ }
+
+ static private PasswordProviderSelector instance = null;
+
+ static public PasswordProviderSelector getInstance() {
+ if (instance == null) {
+ instance = new PasswordProviderSelector();
+ IExtensionRegistry registry = RegistryFactory.getRegistry();
+ registry.addListener(instance, EXTENSION_POINT);
+ }
+ return instance;
+ }
+
+ public void stop() {
+ if (instance != null) {
+ IExtensionRegistry registry = RegistryFactory.getRegistry();
+ registry.addListener(instance, EXTENSION_POINT);
+ instance = null;
+ }
+ }
+
+ private PasswordProviderSelector() {
+ // hides default constructor; use getInstance()
+ }
+
+ public PasswordProviderModuleExt findStorageModule(String expectedID) throws StorageException {
+ if (expectedID != null)
+ expectedID = expectedID.toLowerCase(); // ID is case-insensitive
+ synchronized (modules) {
+ if (modules.containsKey(expectedID))
+ return (PasswordProviderModuleExt) modules.get(expectedID);
+ }
+
+ IExtensionRegistry registry = RegistryFactory.getRegistry();
+ IExtensionPoint point = registry.getExtensionPoint(EXTENSION_POINT);
+ IExtension[] extensions = point.getExtensions();
+
+ ArrayList allAvailableModules = new ArrayList(extensions.length);
+
+ for (int i = 0; i < extensions.length; i++) {
+ String moduleID = extensions[i].getUniqueIdentifier();
+ if (moduleID == null) // IDs on those extensions are mandatory; if not specified, ignore the extension
+ continue;
+ moduleID = moduleID.toLowerCase();
+ if (expectedID != null && !expectedID.equals(moduleID))
+ continue;
+ IConfigurationElement[] elements = extensions[i].getConfigurationElements();
+ if (elements.length == 0)
+ continue;
+ IConfigurationElement element = elements[0]; // only one module is allowed per extension
+ if (!STORAGE_MODULE.equals(element.getName())) {
+ reportError(SecAuthMessages.unexpectedConfigElement, element.getName(), element, null);
+ continue;
+ }
+ String attribute = element.getAttribute(MODULE_PRIORITY);
+ int priority = -1;
+ if (attribute != null) {
+ priority = Integer.parseInt(attribute);
+ if (priority < 0)
+ priority = 0;
+ if (priority > 10)
+ priority = 10;
+ }
+ allAvailableModules.add(new ExtStorageModule(moduleID, element, priority));
+ }
+
+ Collections.sort(allAvailableModules, new Comparator() {
+ public int compare(Object o1, Object o2) {
+ int p1 = ((ExtStorageModule) o1).priority;
+ int p2 = ((ExtStorageModule) o2).priority;
+ return p2 - p1;
+ }
+ });
+
+ for (Iterator i = allAvailableModules.iterator(); i.hasNext();) {
+ ExtStorageModule module = (ExtStorageModule) i.next();
+ Object clazz;
+ try {
+ clazz = module.element.createExecutableExtension(CLASS_NAME);
+ } catch (CoreException e) {
+ reportError(SecAuthMessages.instantiationFailed, module.element.getAttribute(CLASS_NAME), module.element, e);
+ continue;
+ }
+ if (!(clazz instanceof PasswordProvider))
+ continue;
+
+ PasswordProviderModuleExt result = new PasswordProviderModuleExt((PasswordProvider) clazz, module.moduleID);
+
+ // cache the result
+ synchronized (modules) {
+ if (expectedID == null)
+ modules.put(null, result);
+ modules.put(module.moduleID, result);
+ }
+
+ return result;
+ }
+
+ // the secure storage module was not found - error in app's configuration
+ String msg;
+ if (expectedID == null)
+ msg = SecAuthMessages.noSecureStorageModules;
+ else
+ msg = NLS.bind(SecAuthMessages.noSecureStorageModule, expectedID);
+ throw new StorageException(StorageException.NO_SECURE_MODULE, msg);
+ }
+
+ private void reportError(String template, String arg, IConfigurationElement element, Throwable e) {
+ String supplier = element.getContributor().getName();
+ String message = NLS.bind(template, arg, supplier);
+ AuthPlugin.getDefault().logError(message, e);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Synch local cache with the registry
+ public void added(IExtension[] extensions) {
+ clearCaches();
+ }
+
+ public void added(IExtensionPoint[] extensionPoints) {
+ clearCaches();
+ }
+
+ public void removed(IExtension[] extensions) {
+ clearCaches();
+ }
+
+ public void removed(IExtensionPoint[] extensionPoints) {
+ clearCaches();
+ }
+
+ /**
+ * Clear whole cache as priorities might have changed after new modules were added.
+ */
+ private void clearCaches() {
+ synchronized (modules) {
+ modules.clear();
+ SecurePreferencesMapper.clearCaches();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PersistedPath.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PersistedPath.java
new file mode 100644
index 0000000..ccc2dad
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/PersistedPath.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * If the key contains a slash character then we must use a double-slash to indicate
+ * the end of the path/the beginning of the key.
+ */
+public class PersistedPath {
+
+ private static final String DOUBLE_SLASH = "//"; //$NON-NLS-1$
+
+ final private String key;
+ final private String path;
+
+ public PersistedPath(String path, String key) {
+ this.key = key;
+ this.path = path;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String toString() {
+ String result;
+ int pathLength = path == null ? 0 : path.length();
+ if (key.indexOf(IPath.SEPARATOR) == -1) {
+ if (pathLength == 0)
+ result = key;
+ else
+ result = path + IPath.SEPARATOR + key;
+ } else {
+ if (pathLength == 0)
+ result = DOUBLE_SLASH + key;
+ else
+ result = path + DOUBLE_SLASH + key;
+ }
+ return result;
+ }
+
+ public PersistedPath(String fullPath) {
+ // check to see if we have an indicator which tells us where the path ends
+ int index = fullPath.indexOf(DOUBLE_SLASH);
+ if (index == -1) {
+ // we don't have a double-slash telling us where the path ends
+ // so the path is up to the last slash character
+ int lastIndex = fullPath.lastIndexOf(IPath.SEPARATOR);
+ if (lastIndex == -1) {
+ path = null;
+ key = fullPath;
+ } else {
+ path = fullPath.substring(0, lastIndex);
+ key = fullPath.substring(lastIndex + 1);
+ }
+ } else {
+ // the child path is up to the double-slash and the key
+ // is the string after it
+ path = fullPath.substring(0, index);
+ key = fullPath.substring(index + 2);
+ }
+
+ // XXX is this needed?
+ // adjust if we have an absolute path
+ // if (path != null)
+ // if (path.length() == 0)
+ // path = null;
+ // else if (path.charAt(0) == IPath.SEPARATOR)
+ // path = path.substring(1);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferences.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferences.java
new file mode 100644
index 0000000..3776d6d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferences.java
@@ -0,0 +1,515 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import java.io.IOException;
+import java.util.*;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.spec.PBEKeySpec;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.equinox.security.storage.StorageException;
+import org.eclipse.equinox.security.storage.provider.IPreferencesContainer;
+import org.eclipse.equinox.security.storage.provider.IProviderHints;
+import org.eclipse.osgi.util.NLS;
+
+public class SecurePreferences {
+
+ /**
+ * Pseudo-module ID to use when encryption is done with the default password.
+ */
+ protected final static String DEFAULT_PASSWORD_ID = "org.eclipse.equinox.security.noModule"; //$NON-NLS-1$
+
+ /**
+ * Maximum unsuccessful decryption attempts per operation
+ */
+ static protected final int MAX_ATTEMPTS = 20;
+
+ private static final String PATH_SEPARATOR = String.valueOf(IPath.SEPARATOR);
+
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+ private static final String FALSE = "false"; //$NON-NLS-1$
+ private static final String TRUE = "true"; //$NON-NLS-1$
+
+ private boolean removed = false;
+
+ /**
+ * Parent node; null if this is a root node
+ */
+ final protected SecurePreferences parent;
+
+ /**
+ * Name of this node
+ */
+ final private String name;
+
+ /**
+ * Child nodes; created lazily; might be null
+ */
+ protected Map children;
+
+ /**
+ * Values associated with this node; created lazily; might be null
+ */
+ private Map values;
+
+ /**
+ * Cache root node to improve performance a bit
+ */
+ private SecurePreferencesRoot root = null;
+
+ public SecurePreferences(SecurePreferences parent, String name) {
+ this.parent = parent;
+ this.name = name;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ // Navigation
+
+ public SecurePreferences parent() {
+ checkRemoved();
+ return parent;
+ }
+
+ public String name() {
+ checkRemoved();
+ return name;
+ }
+
+ public String absolutePath() {
+ checkRemoved();
+ if (parent == null)
+ return PATH_SEPARATOR;
+ String parentPath = parent.absolutePath();
+ if (PATH_SEPARATOR.equals(parentPath)) // parent is the root node?
+ return parentPath + name;
+ return parentPath + PATH_SEPARATOR + name;
+ }
+
+ public SecurePreferences node(String pathName) {
+ checkRemoved();
+ validatePath(pathName);
+ return navigateToNode(pathName, true);
+ }
+
+ public boolean nodeExists(String pathName) {
+ checkRemoved();
+ validatePath(pathName);
+ return (navigateToNode(pathName, false) != null);
+ }
+
+ public String[] keys() {
+ checkRemoved();
+ if (values == null)
+ return EMPTY_STRING_ARRAY;
+ Set keys = values.keySet();
+ int size = keys.size();
+ String[] result = new String[size];
+ int pos = 0;
+ for (Iterator i = keys.iterator(); i.hasNext();) {
+ result[pos++] = (String) i.next();
+ }
+ return result;
+ }
+
+ public String[] childrenNames() {
+ checkRemoved();
+ if (children == null)
+ return EMPTY_STRING_ARRAY;
+ Set keys = children.keySet();
+ int size = keys.size();
+ String[] result = new String[size];
+ int pos = 0;
+ for (Iterator i = keys.iterator(); i.hasNext();) {
+ result[pos++] = (String) i.next();
+ }
+ return result;
+ }
+
+ protected SecurePreferencesRoot getRoot() {
+ if (root == null) {
+ SecurePreferences result = this;
+ while (result.parent() != null)
+ result = result.parent();
+ root = (SecurePreferencesRoot) result;
+ }
+ return root;
+ }
+
+ protected SecurePreferences navigateToNode(String pathName, boolean create) {
+ if (pathName == null)
+ return getRoot();
+ int pos = pathName.indexOf(IPath.SEPARATOR);
+ if (pos == -1)
+ return getChild(pathName, create);
+ else if (pos == 0) // if path requested is absolute, pass it to the root without "/"
+ return getRoot().navigateToNode(pathName.substring(1), create);
+ else { // if path requested contains segments, isolate top segment and rest
+ String topSegment = pathName.substring(0, pos);
+ String otherSegments = pathName.substring(pos + 1);
+ SecurePreferences child = getChild(topSegment, create);
+ if (child == null && !create)
+ return null;
+ return child.navigateToNode(otherSegments, create);
+ }
+ }
+
+ synchronized private SecurePreferences getChild(String segment, boolean create) {
+ if (children == null) {
+ if (create)
+ children = new HashMap(5);
+ else
+ return null;
+ }
+ SecurePreferences child = (SecurePreferences) children.get(segment);
+ if (!create || (child != null))
+ return child;
+ child = new SecurePreferences(this, segment);
+ children.put(segment, child);
+ return child;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ // Load and save
+
+ public void flush() throws IOException {
+ getRoot().flush();
+ }
+
+ public void flush(Properties properties, String parentsPath) {
+ String thisNodePath;
+ if (name == null)
+ thisNodePath = null;
+ else if (parentsPath == null)
+ thisNodePath = PATH_SEPARATOR + name;
+ else
+ thisNodePath = parentsPath + PATH_SEPARATOR + name;
+
+ if (values != null) {
+ for (Iterator i = values.keySet().iterator(); i.hasNext();) {
+ String key = (String) i.next();
+ PersistedPath extenalTag = new PersistedPath(thisNodePath, key);
+ properties.put(extenalTag.toString(), values.get(key));
+ }
+ }
+
+ if (children != null) {
+ for (Iterator i = children.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ SecurePreferences child = (SecurePreferences) entry.getValue();
+ child.flush(properties, thisNodePath);
+ }
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Basic put() and get()
+
+ public void put(String key, String value, boolean encrypt, SecurePreferencesContainer container) throws StorageException {
+ if (key == null)
+ throw new NullPointerException();
+ checkRemoved();
+
+ if (!encrypt) {
+ CryptoData clearValue = new CryptoData(null, null, value.getBytes());
+ internalPut(key, clearValue.toString());
+ markModified();
+ return;
+ }
+
+ PasswordExt passwordExt = getPassword(container);
+
+ CryptoData encryptedValue;
+ try {
+ encryptedValue = getRoot().getCipher().encrypt(passwordExt, value.getBytes());
+ } catch (StorageException e) {
+ RuntimeException exception = new IllegalStateException();
+ exception.initCause(e);
+ throw exception;
+ }
+ internalPut(key, encryptedValue.toString());
+ markModified();
+ }
+
+ public String get(String key, String def, SecurePreferencesContainer container) throws StorageException {
+ checkRemoved();
+ if (!hasKey(key))
+ return def;
+ String encryptedValue = internalGet(key);
+ if (encryptedValue == null)
+ return null;
+
+ CryptoData data = new CryptoData(encryptedValue);
+ String moduleID = data.getModuleID();
+ if (moduleID == null) { // clear-text value, not encrypted
+ return new String(data.getData());
+ }
+
+ try {
+ byte[] clearText = getRoot().getCipher().decrypt(getPassword(moduleID, container), data);
+ return new String(clearText);
+ } catch (IllegalBlockSizeException e) { // invalid password?
+ throw new StorageException(StorageException.DECRYPTION_ERROR, e);
+ } catch (BadPaddingException e) { // invalid password?
+ throw new StorageException(StorageException.DECRYPTION_ERROR, e);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Password handling routines
+
+ /**
+ * Provides password for a new entry using:
+ * 1) default password, if any
+ * 2a) if options specify usage of specific module, that module is polled to produce password
+ * 2b) otherwise, password provider with highest priority is used to produce password
+ */
+ private PasswordExt getPassword(SecurePreferencesContainer container) throws StorageException {
+ PasswordExt defaultPassword = getDefaultPassword(container);
+ if (defaultPassword != null)
+ return defaultPassword;
+
+ String moduleID = null;
+ if (container.hasOption(IProviderHints.REQUIRED_MODULE_ID)) {
+ Object idHint = container.getOption(IProviderHints.REQUIRED_MODULE_ID);
+ if (idHint instanceof String)
+ moduleID = (String) idHint;
+ }
+ return getRoot().getModulePassword(moduleID, container);
+ }
+
+ /**
+ * Provides password using specified password provider module
+ */
+ private PasswordExt getPassword(String moduleID, SecurePreferencesContainer container) throws StorageException {
+ if (moduleID == null)
+ throw new StorageException(StorageException.NO_SECURE_MODULE, SecAuthMessages.invalidEntryFormat);
+ if (DEFAULT_PASSWORD_ID.equals(moduleID)) {
+ PasswordExt defaultPassword = getDefaultPassword(container);
+ if (defaultPassword != null)
+ return defaultPassword;
+ throw new StorageException(StorageException.NO_SECURE_MODULE, SecAuthMessages.noDefaultPassword);
+ }
+
+ return getRoot().getModulePassword(moduleID, container);
+ }
+
+ /**
+ * Retrieves default password from options, if any
+ */
+ private PasswordExt getDefaultPassword(IPreferencesContainer container) {
+ if (container.hasOption(IProviderHints.DEFAULT_PASSWORD)) {
+ Object passwordHint = container.getOption(IProviderHints.DEFAULT_PASSWORD);
+ if (passwordHint instanceof PBEKeySpec)
+ return new PasswordExt((PBEKeySpec) passwordHint, DEFAULT_PASSWORD_ID);
+ }
+ return null;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ synchronized protected void internalPut(String key, String value) {
+ if (values == null)
+ values = new HashMap(5);
+ values.put(key, value);
+ }
+
+ protected String internalGet(String key) {
+ if (values == null)
+ return null;
+ return (String) values.get(key);
+ }
+
+ protected void markModified() {
+ getRoot().setModified(true);
+ }
+
+ synchronized public void clear() {
+ checkRemoved();
+ if (values != null)
+ values.clear();
+ markModified();
+ }
+
+ synchronized public void remove(String key) {
+ checkRemoved();
+ if (values != null) {
+ values.remove(key);
+ markModified();
+ }
+ }
+
+ public void removeNode() {
+ checkRemoved();
+ if (parent != null)
+ parent.removeNode(name);
+ markRemoved();
+ }
+
+ public void markRemoved() {
+ removed = true;
+ if (children == null)
+ return;
+ for (Iterator i = children.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ SecurePreferences child = (SecurePreferences) entry.getValue();
+ child.markRemoved();
+ }
+ }
+
+ synchronized protected void removeNode(String childName) {
+ if (children == null)
+ return;
+ if (children.remove(childName) != null)
+ markModified();
+ }
+
+ private void checkRemoved() {
+ if (removed)
+ throw new IllegalStateException(NLS.bind(SecAuthMessages.removedNode, name));
+ }
+
+ private void validatePath(String path) {
+ if (isValid(path))
+ return;
+ String msg = NLS.bind(SecAuthMessages.invalidNodePath, path);
+ throw new IllegalArgumentException(msg);
+ }
+
+ /**
+ * In additions to standard Preferences descriptions of paths, the following
+ * conditions apply:
+ * Path can contains ASCII characters between 32 and 126 (alphanumerics and printable
+ * characters).
+ * Path can not contain two or more consecutive forward slashes ('/').
+ * Path can not end with a trailing forward slash.
+ */
+ private boolean isValid(String path) {
+ if (path == null || path.length() == 0)
+ return true;
+ char[] chars = path.toCharArray();
+ boolean lastSlash = false;
+ for (int i = 0; i < chars.length; i++) {
+ if ((chars[i] <= 31) || (chars[i] >= 127))
+ return false;
+ boolean isSlash = (chars[i] == IPath.SEPARATOR);
+ if (lastSlash && isSlash)
+ return false;
+ lastSlash = isSlash;
+ }
+ return (chars[chars.length - 1] != IPath.SEPARATOR);
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////
+ // Variations of get() / put() methods adapted to different data types
+
+ public boolean getBoolean(String key, boolean defaultValue, SecurePreferencesContainer container) throws StorageException {
+ if (!hasKey(key))
+ return defaultValue;
+ String value = get(key, null, container);
+ return value == null ? defaultValue : TRUE.equalsIgnoreCase(value);
+ }
+
+ public void putBoolean(String key, boolean value, boolean encrypt, SecurePreferencesContainer container) throws StorageException {
+ put(key, value ? TRUE : FALSE, encrypt, container);
+ }
+
+ public int getInt(String key, int defaultValue, SecurePreferencesContainer container) throws StorageException {
+ if (!hasKey(key))
+ return defaultValue;
+ String value = get(key, null, container);
+ if (value == null)
+ return defaultValue;
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ public void putInt(String key, int value, boolean encrypt, SecurePreferencesContainer container) throws StorageException {
+ put(key, Integer.toString(value), encrypt, container);
+ }
+
+ public long getLong(String key, long defaultValue, SecurePreferencesContainer container) throws StorageException {
+ if (!hasKey(key))
+ return defaultValue;
+ String value = get(key, null, container);
+ if (value == null)
+ return defaultValue;
+ try {
+ return Long.parseLong(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ public void putLong(String key, long value, boolean encrypt, SecurePreferencesContainer container) throws StorageException {
+ put(key, Long.toString(value), encrypt, container);
+ }
+
+ public float getFloat(String key, float defaultValue, SecurePreferencesContainer container) throws StorageException {
+ if (!hasKey(key))
+ return defaultValue;
+ String value = get(key, null, container);
+ if (value == null)
+ return defaultValue;
+ try {
+ return Float.parseFloat(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ public void putFloat(String key, float value, boolean encrypt, SecurePreferencesContainer container) throws StorageException {
+ put(key, Float.toString(value), encrypt, container);
+ }
+
+ public double getDouble(String key, double defaultValue, SecurePreferencesContainer container) throws StorageException {
+ if (!hasKey(key))
+ return defaultValue;
+ String value = get(key, null, container);
+ if (value == null)
+ return defaultValue;
+ try {
+ return Double.parseDouble(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ public void putDouble(String key, double value, boolean encrypt, SecurePreferencesContainer container) throws StorageException {
+ put(key, Double.toString(value), encrypt, container);
+ }
+
+ public byte[] getByteArray(String key, byte[] defaultValue, SecurePreferencesContainer container) throws StorageException {
+ if (!hasKey(key))
+ return defaultValue;
+ String value = get(key, null, container);
+ return (value == null) ? defaultValue : Base64.decode(value);
+ }
+
+ public void putByteArray(String key, byte[] value, boolean encrypt, SecurePreferencesContainer container) throws StorageException {
+ put(key, Base64.encode(value), encrypt, container);
+ }
+
+ protected boolean hasKey(String key) {
+ checkRemoved();
+ return (values == null) ? false : values.containsKey(key);
+ }
+
+ public boolean isModified() {
+ return getRoot().isModified();
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesContainer.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesContainer.java
new file mode 100644
index 0000000..83b78eb
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesContainer.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.equinox.security.storage.ISecurePreferences;
+import org.eclipse.equinox.security.storage.provider.IPreferencesContainer;
+
+/**
+ * NOTE NOTE NOTE: this Javadoc is implementation details - this is not an API
+ * but a few notes on implementation design.
+ *
+ * For a URL we get one secure preference tree that contains data. The top node
+ * of that tree has a "root" type, it has special properties - the location, status,
+ * and knowledge as to how persist the tree.
+ *
+ * On the user side - let's say we have the following preferences open via factory:
+ *
+ * UserPreferences1 (Options1, URL1)
+ * UserPreferences2 (Options2, URL1)
+ * UserPreferences3 (Options3, URL2)
+ * UserPreferences4 (Options4, URL2)
+ *
+ * When we'll have 2 actual "back end" secure preferences tree with data:
+ *
+ * [UserPreferences1] -> [Options1] +
+ * \
+ * [secure preferences1] <- 1 : 1 -> URL1
+ * /
+ * [UserPreferences2] -> [Options2] +
+ *
+ * [UserPreferences3] -> [Options3] +
+ * \
+ * [secure preferences2] <- 1 : 1 -> URL2
+ * /
+ * [UserPreferences4] -> [Options4] +
+ *
+ * The user-facing nodes are actually a (node + options for this container). User-facing
+ * nodes are called wrappers as they primarily wrap secure preferences nodes.
+ *
+ * Containers are used to combine all wrappers created for the set of options. This way
+ * users don't have to specify options on each get...() / put...() method.
+ *
+ * Additionally, containers cache wrappers so that navigation on preferences tree won't
+ * create new wrappers every time process navigates from one node on the tree to another.
+ *
+ * Password provider modules:
+ *
+ * Note that only a single instance of each password provider is ever created. However,
+ * those instances are passed options as arguments.
+ */
+public class SecurePreferencesContainer implements IPreferencesContainer {
+
+ private Map wrappers = new HashMap(); // node -> SecurePreferencesWrapper
+
+ final private Map options;
+ final private SecurePreferencesRoot root;
+
+ public SecurePreferencesContainer(SecurePreferencesRoot root, Map options) {
+ this.root = root;
+ if (options != null) { // make a copy to avoid problems if original is modified later
+ this.options = new HashMap(options.size());
+ this.options.putAll(options);
+ } else
+ this.options = new HashMap(2);
+ }
+
+ public ISecurePreferences wrapper(SecurePreferences node) {
+ synchronized (wrappers) {
+ if (wrappers.containsKey(node))
+ return (ISecurePreferences) wrappers.get(node);
+ SecurePreferencesWrapper newWrapper = new SecurePreferencesWrapper(node, this);
+ wrappers.put(node, newWrapper);
+ return newWrapper;
+ }
+ }
+
+ public void removeWrapper(SecurePreferences node) {
+ synchronized (wrappers) {
+ if (wrappers.containsKey(node))
+ wrappers.remove(node);
+ }
+ }
+
+ public URL getLocation() {
+ return root.getLocation();
+ }
+
+ public ISecurePreferences getPreferences() {
+ return wrapper(root);
+ }
+
+ // Testing only
+ public SecurePreferencesRoot getRootData() {
+ return root;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Handling of options
+
+ public boolean hasOption(Object key) {
+ synchronized (options) {
+ return options.containsKey(key);
+ }
+ }
+
+ public Object getOption(Object key) {
+ synchronized (options) {
+ return options.get(key);
+ }
+ }
+
+ public Object setOption(Object key, Object value) {
+ synchronized (options) {
+ return options.put(key, value);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesMapper.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesMapper.java
new file mode 100644
index 0000000..b8df1df
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesMapper.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.*;
+import org.eclipse.equinox.internal.security.auth.AuthPlugin;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.equinox.security.storage.ISecurePreferences;
+import org.eclipse.osgi.util.NLS;
+
+public class SecurePreferencesMapper {
+
+ private static Map preferences = new HashMap(); // URL.toString() -> SecurePreferencesRoot
+
+ static public ISecurePreferences open(URL location, Map options) throws IOException {
+ // 1) process location
+ if (location == null)
+ location = StorageUtils.getDefaultLocation();
+ if (!StorageUtils.isFile(location))
+ // at this time we only accept file URLs; check URL type right away
+ throw new IOException(NLS.bind(SecAuthMessages.loginFileURL, location.toString()));
+
+ // 2) see if there is already SecurePreferencesRoot at that location; if not open a new one
+ String key = location.toString();
+ SecurePreferencesRoot root;
+ if (preferences.containsKey(key))
+ root = (SecurePreferencesRoot) preferences.get(key);
+ else {
+ root = new SecurePreferencesRoot(location);
+ preferences.put(key, root);
+ }
+
+ // 3) create container with the options passed in
+ SecurePreferencesContainer container = new SecurePreferencesContainer(root, options);
+ return container.getPreferences();
+ }
+
+ static public void stop() {
+ synchronized (preferences) {
+ for (Iterator i = preferences.values().iterator(); i.hasNext();) {
+ SecurePreferencesRoot provider = (SecurePreferencesRoot) i.next();
+ try {
+ provider.flush();
+ } catch (IOException e) {
+ AuthPlugin.getDefault().logError(SecAuthMessages.errorOnSave, e);
+ }
+ }
+ preferences.clear();
+ }
+ }
+
+ // Not an API; links to the dynamic bundles
+ static public void clearCaches() {
+ synchronized (preferences) {
+ for (Iterator i = preferences.values().iterator(); i.hasNext();) {
+ SecurePreferencesRoot provider = (SecurePreferencesRoot) i.next();
+ provider.clearPasswordCache();
+ }
+ }
+ }
+
+ // Not exposed as API; mostly intended for testing
+ static public void close(SecurePreferencesRoot root) {
+ if (root == null)
+ return;
+ synchronized (preferences) {
+ for (Iterator i = preferences.values().iterator(); i.hasNext();) {
+ SecurePreferencesRoot provider = (SecurePreferencesRoot) i.next();
+ if (!root.equals(provider))
+ continue;
+ i.remove();
+ break;
+ }
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesRoot.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesRoot.java
new file mode 100644
index 0000000..75e6998
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesRoot.java
@@ -0,0 +1,228 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.spec.PBEKeySpec;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.equinox.security.storage.StorageException;
+import org.eclipse.equinox.security.storage.provider.IProviderHints;
+
+/**
+ * Root secure preference node. In addition to usual things it stores location, modified
+ * status, encryption algorithm, and performs save and load.
+ */
+public class SecurePreferencesRoot extends SecurePreferences implements IStorageConstants {
+
+ private static final String VERSION_KEY = "org.eclipse.equinox.security.preferences.version"; //$NON-NLS-1$
+ private static final String VERSION_VALUE = "1"; //$NON-NLS-1$
+
+ /**
+ * Node path reserved for persisted preferences of the modules.
+ */
+ static final public String PROVIDER_PATH = "org.eclipse.equinox.security.storage.impl"; //$NON-NLS-1$
+
+ /**
+ * Description of the property file - information only
+ */
+ final private static String description = "Equinox secure storage version 1.0"; //$NON-NLS-1$
+
+ /**
+ * The node used by the secure preferences itself
+ */
+ private final static String PROVIDER_NODE = "/org.eclipse.equinox.secure.storage"; //$NON-NLS-1$
+
+ /**
+ * Node used to store password verification tokens
+ */
+ private final static String PASSWORD_VERIFICATION_NODE = PROVIDER_NODE + "/verification"; //$NON-NLS-1$
+
+ /**
+ * Text used to verify password
+ */
+ private final static String PASSWORD_VERIFICATION_SAMPLE = "-> brown fox jumped over lazy dog <-"; //$NON-NLS-1$
+
+ final private URL location;
+
+ private boolean modified = false;
+
+ private JavaEncryption cipher = new JavaEncryption();
+
+ private Map passwordCache = new HashMap(5); // cached passwords: module ID -> PasswordExt
+
+ public SecurePreferencesRoot(URL location) throws IOException {
+ super(null, null);
+ this.location = location;
+ load();
+ }
+
+ public URL getLocation() {
+ return location;
+ }
+
+ public JavaEncryption getCipher() {
+ return cipher;
+ }
+
+ public boolean isModified() {
+ return modified;
+ }
+
+ public void setModified(boolean modified) {
+ this.modified = modified;
+ }
+
+ public void load() throws IOException {
+ if (location == null)
+ return;
+
+ Properties properties = new Properties();
+ InputStream is = null;
+ try {
+ is = StorageUtils.getInputStream(location);
+ if (is != null)
+ properties.load(is);
+ } finally {
+ if (is != null)
+ is.close();
+ }
+
+ // In future new versions could be added
+ Object version = properties.get(VERSION_KEY);
+ if ((version != null) && !VERSION_VALUE.equals(version))
+ return;
+ properties.remove(VERSION_KEY);
+
+ // Process encryption algorithms
+ if (properties.containsKey(CIPHER_KEY) && properties.containsKey(KEY_FACTORY_KEY)) {
+ Object cipherAlgorithm = properties.get(CIPHER_KEY);
+ Object keyFactoryAlgorithm = properties.get(KEY_FACTORY_KEY);
+ if ((cipherAlgorithm instanceof String) && (keyFactoryAlgorithm instanceof String))
+ cipher.setAlgorithms((String) cipherAlgorithm, (String) keyFactoryAlgorithm);
+ properties.remove(CIPHER_KEY);
+ properties.remove(KEY_FACTORY_KEY);
+ }
+
+ for (Iterator i = properties.keySet().iterator(); i.hasNext();) {
+ Object externalKey = i.next();
+ Object value = properties.get(externalKey);
+ if (!(externalKey instanceof String))
+ continue;
+ if (!(value instanceof String))
+ continue;
+ PersistedPath storedPath = new PersistedPath((String) externalKey);
+ if (storedPath.getKey() == null)
+ continue;
+
+ SecurePreferences node = node(storedPath.getPath());
+ // don't use regular put() method as that would mark node as dirty
+ node.internalPut(storedPath.getKey(), (String) value);
+ }
+ }
+
+ public void flush() throws IOException {
+ if (location == null)
+ return;
+ if (!modified)
+ return;
+
+ Properties properties = new Properties();
+ properties.put(VERSION_KEY, VERSION_VALUE);
+
+ // remember encyption algorithms
+ String cipherAlgorithm = cipher.getCipherAlgorithm();
+ if (cipherAlgorithm != null) {
+ properties.put(CIPHER_KEY, cipherAlgorithm);
+ properties.put(KEY_FACTORY_KEY, cipher.getKeyFactoryAlgorithm());
+ }
+
+ // save all user properties
+ flush(properties, null);
+
+ // output
+ OutputStream stream = null;
+ try {
+ stream = StorageUtils.getOutputStream(location);
+ properties.store(stream, description);
+ modified = false;
+ } finally {
+ if (stream != null)
+ stream.close();
+ }
+ }
+
+ public PasswordExt getModulePassword(String moduleID, SecurePreferencesContainer container) throws StorageException {
+ if (DEFAULT_PASSWORD_ID.equals(moduleID)) // this should never happen but add this check just in case
+ throw new StorageException(StorageException.NO_PASSWORD, SecAuthMessages.loginNoPassword);
+
+ PasswordProviderModuleExt moduleExt = PasswordProviderSelector.getInstance().findStorageModule(moduleID);
+ synchronized (passwordCache) {
+ String key = moduleExt.getID();
+ if (passwordCache.containsKey(key))
+ return (PasswordExt) passwordCache.get(key);
+
+ // is there password verification string already?
+ SecurePreferences node = node(PASSWORD_VERIFICATION_NODE);
+ boolean newPassword = !node.hasKey(key);
+ container.setOption(IProviderHints.NEW_PASSWORD, new Boolean(newPassword));
+
+ boolean validPassword = false;
+ PasswordExt passwordExt = null;
+
+ for (int i = 0; i < MAX_ATTEMPTS; i++) {
+ PBEKeySpec password = moduleExt.login(container);
+ if (password == null)
+ return null;
+ passwordExt = new PasswordExt(password, key);
+ if (newPassword) {
+ CryptoData encryptedValue = getCipher().encrypt(passwordExt, PASSWORD_VERIFICATION_SAMPLE.getBytes());
+ node.internalPut(key, encryptedValue.toString());
+ markModified();
+ validPassword = true;
+ break;
+ }
+ // verify password using sample text
+ String encryptedData = node.internalGet(key);
+ CryptoData data = new CryptoData(encryptedData);
+ try {
+ byte[] decryptedData = getCipher().decrypt(passwordExt, data);
+ if (PASSWORD_VERIFICATION_SAMPLE.equals(new String(decryptedData))) {
+ validPassword = true;
+ break;
+ }
+ } catch (IllegalBlockSizeException e) {
+ if (!moduleExt.changePassword(e, container))
+ break;
+ moduleExt.logout(container);
+ } catch (BadPaddingException e) {
+ if (!moduleExt.changePassword(e, container))
+ break;
+ moduleExt.logout(container);
+ }
+ }
+ if (validPassword) {
+ passwordCache.put(key, passwordExt);
+ return passwordExt;
+ }
+ throw new StorageException(StorageException.NO_PASSWORD, SecAuthMessages.loginNoPassword);
+ }
+ }
+
+ public void clearPasswordCache() {
+ synchronized (passwordCache) {
+ passwordCache.clear();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesWrapper.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesWrapper.java
new file mode 100644
index 0000000..2840896
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SecurePreferencesWrapper.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import java.io.IOException;
+import org.eclipse.equinox.security.storage.ISecurePreferences;
+import org.eclipse.equinox.security.storage.StorageException;
+
+/**
+ * This class combines secure preferences node with specific container. See
+ * container for the description of relationships.
+ */
+public class SecurePreferencesWrapper implements ISecurePreferences {
+
+ final protected SecurePreferences node;
+
+ final protected SecurePreferencesContainer container;
+
+ public SecurePreferencesWrapper(SecurePreferences node, SecurePreferencesContainer container) {
+ this.node = node;
+ this.container = container;
+ }
+
+ // Testing only
+ public SecurePreferencesContainer getContainer() {
+ return container;
+ }
+
+ public String absolutePath() {
+ return node.absolutePath();
+ }
+
+ public String[] childrenNames() {
+ return node.childrenNames();
+ }
+
+ public void clear() {
+ node.clear();
+ }
+
+ public void flush() throws IOException {
+ node.flush();
+ }
+
+ public String[] keys() {
+ return node.keys();
+ }
+
+ public String name() {
+ return node.name();
+ }
+
+ public void remove(String key) {
+ node.remove(key);
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == null)
+ return false;
+ if (!(obj instanceof SecurePreferencesWrapper))
+ return false;
+ SecurePreferencesWrapper other = (SecurePreferencesWrapper) obj;
+ return container.equals(other.container) && node.equals(other.node);
+ }
+
+ public int hashCode() {
+ String tmp = Integer.toString(container.hashCode()) + '|' + Integer.toString(node.hashCode());
+ return tmp.hashCode();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Navigation
+
+ public ISecurePreferences node(String pathName) {
+ return container.wrapper(node.node(pathName));
+ }
+
+ public ISecurePreferences parent() {
+ SecurePreferences parent = node.parent();
+ if (parent == null)
+ return null;
+ return container.wrapper(node.parent());
+ }
+
+ public boolean nodeExists(String pathName) {
+ return node.nodeExists(pathName);
+ }
+
+ public void removeNode() {
+ container.removeWrapper(node);
+ node.removeNode();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////
+ // puts() and gets()
+
+ public String get(String key, String def) throws StorageException {
+ return node.get(key, def, container);
+ }
+
+ public void put(String key, String value, boolean encrypt) throws StorageException {
+ node.put(key, value, encrypt, container);
+ }
+
+ public boolean getBoolean(String key, boolean def) throws StorageException {
+ return node.getBoolean(key, def, container);
+ }
+
+ public void putBoolean(String key, boolean value, boolean encrypt) throws StorageException {
+ node.putBoolean(key, value, encrypt, container);
+ }
+
+ public int getInt(String key, int def) throws StorageException {
+ return node.getInt(key, def, container);
+ }
+
+ public void putInt(String key, int value, boolean encrypt) throws StorageException {
+ node.putInt(key, value, encrypt, container);
+ }
+
+ public float getFloat(String key, float def) throws StorageException {
+ return node.getFloat(key, def, container);
+ }
+
+ public void putFloat(String key, float value, boolean encrypt) throws StorageException {
+ node.putFloat(key, value, encrypt, container);
+ }
+
+ public long getLong(String key, long def) throws StorageException {
+ return node.getLong(key, def, container);
+ }
+
+ public void putLong(String key, long value, boolean encrypt) throws StorageException {
+ node.putLong(key, value, encrypt, container);
+ }
+
+ public double getDouble(String key, double def) throws StorageException {
+ return node.getDouble(key, def, container);
+ }
+
+ public void putDouble(String key, double value, boolean encrypt) throws StorageException {
+ node.putDouble(key, value, encrypt, container);
+ }
+
+ public byte[] getByteArray(String key, byte[] def) throws StorageException {
+ return node.getByteArray(key, def, container);
+ }
+
+ public void putByteArray(String key, byte[] value, boolean encrypt) throws StorageException {
+ node.putByteArray(key, value, encrypt, container);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SlashEncode.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SlashEncode.java
new file mode 100644
index 0000000..623d8c8
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/SlashEncode.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+/**
+ * Utility class to encode forward slash characters so that strings containing
+ * forward slashes can be used as node names with secure preferences. It is
+ * the responsibility of the consumer to manually encode such strings before
+ * attempting to obtain corresponding nodes from secure preferences.
+ * <p>
+ * Internally, the class uses a subset of JIT encoding. The forward slashes
+ * and backward slashes are encoded.
+ * </p><p>
+ * This class is not intended to be instantiated or subclassed by users.
+ * </p>
+ */
+final public class SlashEncode {
+
+ final private static char SLASH = '/';
+ final private static char BACK_SLASH = '\\';
+
+ final private static String ENCODED_SLASH = "\\2f"; //$NON-NLS-1$
+ final private static String ENCODED_BACK_SLASH = "\\5c"; //$NON-NLS-1$
+
+ static public String decode(String str) {
+ if (str == null)
+ return null;
+ if (str == null)
+ return null;
+ int size = str.length();
+ if (size == 0)
+ return str;
+
+ StringBuffer processed = new StringBuffer(size);
+ int processedPos = 0;
+
+ for (int i = 0; i < size; i++) {
+ char c = str.charAt(i);
+ if (c == BACK_SLASH) {
+ if (i + 2 >= size)
+ continue;
+ String encoded = str.substring(i, i + 3);
+ char decoded = 0;
+ if (ENCODED_SLASH.equals(encoded))
+ decoded = SLASH;
+ else if (ENCODED_BACK_SLASH.equals(encoded))
+ decoded = BACK_SLASH;
+ if (decoded == 0)
+ continue;
+ if (i > processedPos)
+ processed.append(str.substring(processedPos, i));
+ processed.append(decoded);
+ processedPos = i + 3;
+ i += 2; // skip over remaining encoded portion
+ }
+ }
+ if (processedPos == 0)
+ return str;
+ if (processedPos < size)
+ processed.append(str.substring(processedPos));
+ return new String(processed);
+ }
+
+ static public String encode(String str) {
+ if (str == null)
+ return null;
+ int size = str.length();
+ if (size == 0)
+ return str;
+
+ StringBuffer processed = new StringBuffer(size);
+ int processedPos = 0;
+
+ for (int i = 0; i < size; i++) {
+ char c = str.charAt(i);
+ if (c == SLASH || c == BACK_SLASH) {
+ if (i > processedPos)
+ processed.append(str.substring(processedPos, i));
+ if (c == SLASH)
+ processed.append(ENCODED_SLASH);
+ else if (c == BACK_SLASH)
+ processed.append(ENCODED_BACK_SLASH);
+ processedPos = i + 1;
+ }
+ }
+ if (processedPos == 0)
+ return str;
+ if (processedPos < size)
+ processed.append(str.substring(processedPos));
+ return new String(processed);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/StorageUtils.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/StorageUtils.java
new file mode 100644
index 0000000..add19bf
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/StorageUtils.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.internal.security.storage;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import org.eclipse.equinox.internal.security.auth.AuthPlugin;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+
+/**
+ * PLEASE READ BEFORE CHANGING THIS FILE
+ *
+ * At present most of the methods expect only file URLs. The API methods
+ * take URLs for possible future expansion, and there is some code below
+ * that would work with some other URL types, but the only supported URL
+ * types at this time are file URLs. Also note that URL paths should not
+ * be encoded (spaces should be spaces, not "%x20").
+ *
+ * On encoding: Java documentation recommends using File.toURI().toURL().
+ * However, in this process non-alphanumeric characters (including spaces)
+ * get encoded and can not be used with the rest of Eclipse methods that
+ * expect non-encoded strings.
+ */
+public class StorageUtils {
+
+ /**
+ * Default name of the storage file
+ */
+ final private static String propertiesFileName = "secure_preferences.equinox"; //$NON-NLS-1$
+
+ /**
+ * Default locations:
+ * 1) user.home
+ * 2) Eclipse config location
+ */
+ static public URL getDefaultLocation() throws IOException {
+ String userHome = System.getProperty("user.home"); //$NON-NLS-1$
+ if (userHome != null) {
+ File file = new File(userHome, propertiesFileName);
+ // NOTE: Don't use File.toURI().toURL() as it will escape space characters and such.
+ // The escaped sequence will fail later when we try to open a stream on it.
+ return file.toURL();
+ }
+ // use install location
+ URL installLocation = AuthPlugin.getDefault().getConfigURL();
+ if (installLocation != null && isFile(installLocation)) {
+ File file = new File(installLocation.getPath(), propertiesFileName);
+ // NOTE: Same thing about toURI() as above
+ return file.toURL();
+ }
+ // practically, we never should reach this point but just in case:
+ throw new IOException(SecAuthMessages.loginNoDefaultLocation);
+ }
+
+ static public OutputStream getOutputStream(URL url) throws IOException {
+ if (isFile(url)) {
+ File file = new File(url.getPath());
+ return new FileOutputStream(file);
+ }
+ // note that code below does not work for File URLs - "by design" Java
+ // does not support creating output streams on file URLs. Code below should work
+ // for HTTP URLs; no idea as to the other types of URLs
+ URLConnection connection = url.openConnection();
+ connection.setDoOutput(true);
+ return connection.getOutputStream();
+ }
+
+ static public InputStream getInputStream(URL url) throws IOException {
+ if (url == null)
+ return null;
+ try {
+ return url.openStream();
+ } catch (FileNotFoundException e) {
+ return null; // this is all right, means new file
+ }
+ }
+
+ static public boolean delete(URL url) {
+ if (isFile(url)) {
+ File file = new File(url.getPath());
+ return file.delete();
+ }
+ return false;
+ }
+
+ static public boolean exists(URL url) {
+ if (isFile(url)) {
+ File file = new File(url.getPath());
+ return file.exists();
+ }
+ return true;
+ }
+
+ static public boolean isFile(URL url) {
+ return ("file".equals(url.getProtocol())); //$NON-NLS-1$
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/ISecureContext.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/ISecureContext.java
new file mode 100644
index 0000000..b44e028
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/ISecureContext.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.auth;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import org.eclipse.equinox.security.auth.event.*;
+
+/**
+ * The ISecureContext is the central entry point for the authentication support.
+ * Use it to perform login, logout, and retrieve information associated with the security
+ * subject.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface ISecureContext {
+
+ /**
+ * Call this method to perform a login.
+ * @see LoginContext#login()
+ * @throws LoginException
+ */
+ public void login() throws LoginException;
+
+ /**
+ * Call this method to perform a logout.
+ * @see LoginContext#logout()
+ * @throws LoginException
+ */
+ public void logout() throws LoginException;
+
+ /**
+ * Retrieves the current Subject. Calling this method will force a login to occur
+ * if the user is not already logged in.
+ * @see LoginContext#getSubject()
+ * @return the Subject
+ */
+ public Subject getSubject() throws LoginException;
+
+ /**
+ * Adds listener to be notified on security-related events.
+ * @param listener the listener to be registered
+ * @see ILoginListener
+ * @see ILogoutListener
+ */
+ public void registerListener(ISecurityListener listener);
+
+ /**
+ * Removes listener previously registered to receive notifications
+ * on security-related events.
+ * @param listener the listener to be unregistered
+ * @see ILoginListener
+ * @see ILogoutListener
+ */
+ public void unregisterListener(ISecurityListener listener);
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/SecurePlatform.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/SecurePlatform.java
new file mode 100644
index 0000000..4bc0ad1
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/SecurePlatform.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.auth;
+
+import java.net.URL;
+import javax.security.auth.callback.CallbackHandler;
+import org.eclipse.equinox.internal.security.auth.SecureContext;
+
+/**
+ * The SecurePlatform class is the entry point for the login support for the platform.
+ * Use it to create security context.
+ * <p>
+ * This class is not intended to be instantiated or extended by clients.
+ * </p>
+ */
+final public class SecurePlatform {
+
+ /**
+ * Creates application-specific security context. The security context then can be used
+ * to perform login, logout, and obtain Subject information.
+ * <p>
+ * Due to the way default Java Configuration is initialized, this context should be
+ * created first. If standard JAAS files are used with the standard configuration,
+ * the initialization will fail unless this context created first, prior to
+ * any calls to {@link #createContext(String)}.
+ * </p>
+ * @param configName the name of login configuration to use
+ * @param configFile points to the standard JASS configuration file
+ * @return new security context
+ */
+ public static ISecureContext createContext(String configName, URL configFile) {
+ return new SecureContext(configName, configFile, null);
+ }
+
+ /**
+ * Creates application-specific security context. The security context then can be used
+ * to perform login, logout, and obtain Subject information.
+ * <p>
+ * Due to the way default Java Configuration is initialized, this context should be
+ * created first. If standard JAAS files are used with the standard configuration,
+ * the initialization will fail unless this context created first, prior to
+ * any calls to {@link #createContext(String)}.
+ * </p>
+ * @param configName the name of login configuration to use
+ * @param configFile points to the standard JASS configuration file
+ * @param handler optional callback handler, might be <code>null</code>
+ * @return new security context
+ */
+ public static ISecureContext createContext(String configName, URL configFile, CallbackHandler handler) {
+ return new SecureContext(configName, configFile, handler);
+ }
+
+ /**
+ * Creates application-specific security context. The security context then can be used
+ * to perform login, logout, and obtain Subject information.
+ * @param configName the name of login configuration to use
+ * @param configFile points to the standard JASS configuration file
+ * @return new security context
+ */
+ public static ISecureContext createContext(String configName) {
+ return new SecureContext(configName);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/credentials/CredentialsFactory.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/credentials/CredentialsFactory.java
new file mode 100644
index 0000000..a068e7f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/credentials/CredentialsFactory.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.auth.credentials;
+
+import java.security.Principal;
+import javax.crypto.spec.PBEKeySpec;
+import javax.security.auth.Subject;
+import org.eclipse.equinox.internal.security.credentials.EquinoxPrivateCredential;
+import org.eclipse.equinox.internal.security.credentials.EquinoxPublicCredential;
+
+/**
+ * This factory can be used by login modules to create Equinox public and private
+ * credentials. It is expected that as a result of successful login credentials
+ * are added to the {@link Subject}.
+ * <p>
+ * This class is not intended to be instantiated or extended by clients.
+ * </p>
+ */
+final public class CredentialsFactory {
+
+ /**
+ * Login modules can use this method to create new public credentials as a result
+ * of the login process.
+ * @see Subject#getPublicCredentials()
+ * @param name user's name
+ * @param primaryRole user's primary role, <code>null</code> if not available
+ * @param providerID the ID of the creator of this public credential; if provider was
+ * described as an extension, use the extension ID
+ * @return new public credential
+ */
+ static public IPublicCredential publicCredential(String name, Principal primaryRole, String providerID) {
+ return new EquinoxPublicCredential(name, primaryRole, providerID);
+ }
+
+ /**
+ * Login modules can use this method to create new public credentials as a result
+ * of the login process.
+ * @see Subject#getPublicCredentials()
+ * @param name user's name
+ * @param roles user's roles, <code>null</code> if not available
+ * @param providerID the ID of the creator of this public credential; if provider was
+ * described as an extension, use the extension ID
+ * @return new public credential
+ */
+ static public IPublicCredential publicCredential(String name, Principal[] roles, String providerID) {
+ return new EquinoxPublicCredential(name, roles, providerID);
+ }
+
+ /**
+ * Login modules can use this method to create new private credentials.
+ * @see Subject#getPrivateCredentials()
+ * @param privateKey the private key to be stored in this credential
+ * @param providerID the ID of the creator of this private credential; if provider was
+ * described as an extension, use the extension ID
+ * @return new private credential
+ */
+ static public IPrivateCredential privateCredential(PBEKeySpec privateKey, String providerID) {
+ return new EquinoxPrivateCredential(privateKey, providerID);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/credentials/IPrivateCredential.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/credentials/IPrivateCredential.java
new file mode 100644
index 0000000..85ef38a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/credentials/IPrivateCredential.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.auth.credentials;
+
+import javax.crypto.spec.PBEKeySpec;
+import javax.security.auth.Subject;
+
+/**
+ * This interface describes private credentials added by the Equinox login modules.
+ * <p>
+ * This interface should not be extended by clients.
+ * </p>
+ * @see Subject#getPrivateCredentials()
+ */
+public interface IPrivateCredential {
+
+ /**
+ * Returns private key stored in this credential
+ * @return private key
+ */
+ public PBEKeySpec getPrivateKey();
+
+ /**
+ * ID of the provider of this private credential.
+ * @return provider ID
+ */
+ public String getProviderID();
+
+ /**
+ * Clears private key from memory.
+ */
+ public void clear();
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/credentials/IPublicCredential.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/credentials/IPublicCredential.java
new file mode 100644
index 0000000..acbfb83
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/credentials/IPublicCredential.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.auth.credentials;
+
+import java.security.Principal;
+import javax.security.auth.Subject;
+
+/**
+ * This interface describes public credentials added by the Equinox login modules.
+ * <p>
+ * This interface should not be extended by clients.
+ * </p>
+ * @see Subject#getPublicCredentials()
+ */
+public interface IPublicCredential extends Principal {
+
+ /**
+ * Returns user's primary role, if set. Might return <code>null</code> if
+ * primary role is not set.
+ * @return user's primary role. Returns <code>null</code> if there is no primary role.
+ */
+ public Principal getPrimaryRole();
+
+ /**
+ * Returns user's roles. Might return <code>null</code> if there are no roles.
+ * @return user's roles. Returns <code>null</code> if there are no roles.
+ */
+ public Principal[] getRoles();
+
+ /**
+ * ID of the provider of this public credential.
+ * @return provider ID
+ */
+ public String getProviderID();
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/event/ILoginListener.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/event/ILoginListener.java
new file mode 100644
index 0000000..b81a3e3
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/event/ILoginListener.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.auth.event;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+
+/**
+ * Implement this interface on security event listeners to
+ * receive notifications of login process.
+ */
+public interface ILoginListener extends ISecurityListener {
+
+ /**
+ * This method is called before login starts.
+ * @param subject the subject being authenticated, might be <code>null</code>
+ * if there is no subject associated the context at this time
+ */
+ void onLoginStart(Subject subject);
+
+ /**
+ * This method is called after login sequence is finished. If login
+ * exception is not null, the login failed.
+ * @param subject the subject being authenticated, might be <code>null</code>
+ * if there is no subject associated the context at this time
+ * @param loginException <code>null</code> if login succeeded, otherwise contains
+ * exception caused login to fail
+ */
+ void onLoginFinish(Subject subject, LoginException loginException);
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/event/ILogoutListener.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/event/ILogoutListener.java
new file mode 100644
index 0000000..d5d5616
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/event/ILogoutListener.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.auth.event;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+
+/**
+ * Implement this interface on security event listeners to
+ * receive notifications of logout process.
+ */
+public interface ILogoutListener extends ISecurityListener {
+
+ /**
+ * This method is called before logout starts.
+ * @param subject the authenticated subject, might be <code>null</code>
+ * if there is no subject associated the context at this time
+ */
+ void onLogoutStart(Subject subject);
+
+ /**
+ * This method is called after logout sequence finishes. If logout
+ * exception is not null, the logout failed.
+ * @param subject the authenticated subject, might be <code>null</code>
+ * if there is no subject associated the context at this time
+ * @param logoutException <code>null</code> if logout succeeded, otherwise contains
+ * exception caused logout to fail
+ */
+ void onLogoutFinish(Subject subject, LoginException logoutException);
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/event/ISecurityListener.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/event/ISecurityListener.java
new file mode 100644
index 0000000..7ebd75d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/event/ISecurityListener.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.auth.event;
+
+/**
+ * This is a common interface that tags a class that can be registered
+ * as a listener for security events.
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ * @see ILoginListener
+ * @see ILogoutListener
+ */
+public interface ISecurityListener {
+ // empty
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/module/ExtensionLoginModule.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/module/ExtensionLoginModule.java
new file mode 100644
index 0000000..a85b7b1
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/auth/module/ExtensionLoginModule.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.auth.module;
+
+import java.util.Map;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import org.eclipse.equinox.internal.security.auth.ext.loader.ExtLoginModuleLoader;
+
+/**
+ * This class allows login modules specified via <code>loginModule</code> extension point
+ * to be included in the login configurations.
+ * <p>
+ * To include your login module in a login configuration, specify this class as a login module
+ * using its qualified Java name. Options specified for such entry should contain an option named
+ * <code>extensionId</code> set to the qualified ID of the extension describing your login module.
+ * </p><p>
+ * This class should not be extended or instantiated directly.
+ * </p>
+ */
+final public class ExtensionLoginModule implements LoginModule {
+
+ /**
+ * The key for the option that specifies an extension describing the actual login module
+ */
+ static final public String OPTION_MODULE_POINT = "extensionId"; //$NON-NLS-1$
+
+ private LoginModule target = null;
+
+ /**
+ * Constructor
+ */
+ public ExtensionLoginModule() {
+ // place holder
+ }
+
+ /* (non-Javadoc)
+ * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
+ */
+ public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
+ target = ExtLoginModuleLoader.load(options);
+ target.initialize(subject, callbackHandler, sharedState, options);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.security.auth.spi.LoginModule#login()
+ */
+ public boolean login() throws LoginException {
+ return target.login();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.security.auth.spi.LoginModule#commit()
+ */
+ public boolean commit() throws LoginException {
+ return target.commit();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.security.auth.spi.LoginModule#abort()
+ */
+ public boolean abort() throws LoginException {
+ return target.abort();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.security.auth.spi.LoginModule#logout()
+ */
+ public boolean logout() throws LoginException {
+ return target.logout();
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/EncodingUtils.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/EncodingUtils.java
new file mode 100644
index 0000000..e57860c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/EncodingUtils.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.storage;
+
+import org.eclipse.equinox.internal.security.storage.Base64;
+import org.eclipse.equinox.internal.security.storage.SlashEncode;
+
+/**
+ * Collection of helper methods.
+ * <p>
+ * This class is not intended to be instantiated or extended by clients.
+ * </p>
+ */
+final public class EncodingUtils {
+
+ /**
+ * Encode strings containing forward slashes so that they can be used as node names
+ * with secure preferences. It is the responsibility of the consumer to manually encode
+ * such strings before attempting to obtain corresponding nodes from secure preferences.
+ * <p>
+ * Internally, the class uses a subset of JIT encoding. The forward slashes
+ * and backward slashes are encoded.
+ * </p>
+ * @see #decodeSlashes(String)
+ * @param nodeName string to be encoded
+ * @return encoded string, <code>null</code> if argument was <code>null</code>
+ */
+ static public String encodeSlashes(String nodeName) {
+ return SlashEncode.encode(nodeName);
+ }
+
+ /**
+ * Decode strings previously encoded with the {@link #encodeSlashes(String)} method.
+ * @param nodeName string to be decoded
+ * @return decoded string, <code>null</code> if argument was <code>null</code>
+ */
+ static public String decodeSlashes(String nodeName) {
+ return SlashEncode.decode(nodeName);
+ }
+
+ /**
+ * Provides Base64 encoding of the data. This Base64 encoding does not insert
+ * end-of-line characters (but can properly decode strings with EOLs inserted).
+ * @param bytes data to be encoded
+ * @return data encoded as Base64 string
+ */
+ static public String encodeBase64(byte[] bytes) {
+ return Base64.encode(bytes);
+ }
+
+ /**
+ * Provides decoding of Base64-encoded string
+ * @param string data encoded as Base64
+ * @return decoded data
+ */
+ static public byte[] decodeBase64(String string) {
+ return Base64.decode(string);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/ISecurePreferences.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/ISecurePreferences.java
new file mode 100644
index 0000000..b36fda4
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/ISecurePreferences.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.storage;
+
+import java.io.IOException;
+
+/**
+ * This interface describes functionality provided by secure preferences. Secure
+ * preferences can be used to persist sensitive information in an encrypted form.
+ * <p>
+ * Logically, secure preferences combine functionality of a keyring (keystore) and
+ * {@link org.osgi.service.prefs.Preferences}.
+ * </p><p>
+ * For an excellent detailed description of the preferences functionality see
+ * {@link org.osgi.service.prefs.Preferences}. To recap in a short form, preferences
+ * provide a tree. Nodes on that tree can be used to specify context. For instance,
+ * root node could have a child node called "cvs" to store information related to CVS
+ * integration.
+ * </p><p>
+ * Each node can have a map of keys with associated values. For instance, to store
+ * password for the CVS repository located on eclipse.org we could use the following
+ * code:
+ * </p>
+ * <pre>
+ * ISecurePreferences root = SecurePreferencesFactory.getDefault();
+ * ISecurePreferences node = root.node("cvs/eclipse.org");
+ * node.put("password", myPassword, true);
+ * </pre>
+ * <p>
+ * This interface has the following differences from the {@link org.osgi.service.prefs.Preferences}:
+ * <ul>
+ * <li>get...() and put...() methods throw StorageException</li>
+ * <li>put...() methods have an extra argument bEncrypt</li>
+ * <li>Methods that used to throw BackingStoreException will be throwing more detailed StorageException</li>
+ * <li>Navigation on preferences tree will return ISecurePreferences, as opposing to Preferences</li>
+ * <li>flush() throws IOException</li>
+ * <li>sync() method is removed</li>
+ * </ul>
+ * </p><p>
+ * On the keyring side, when adding a key to the node, you can ask framework to encrypt it. Framework
+ * will lazily acquire password from password provider and use it to encrypt all new entries added
+ * to the secure preferences tree in this session.
+ * </p><p>
+ * It is worthwhile to reiterate that same limitations as {@link org.osgi.service.prefs.Preferences}
+ * apply to the node names. One non-trivial limitation is that node names can not contain forward
+ * slashes. For convenience, utility methods {@link EncodingUtils#encodeSlashes(String)} and
+ * {@link EncodingUtils#decodeSlashes(String)} are provided to work around this limitation.
+ * </p><p>
+ * Also note that secure preferences only intended to store relatively small size data, such as
+ * passwords. If you need to securely store large objects, consider encrypting such objects in
+ * a symmetric way using randomly generated password and use secure preferences to store the password.
+ * </p><p>
+ * It secure preferences were modified, the framework will automatically save them on shutdown.
+ * </p><p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ */
+public interface ISecurePreferences {
+
+ /**
+ * Stores a value associated with the key in this node.
+ * @param key key with which the value is going to be associated
+ * @param value value to store
+ * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value
+ * does not need to be encrypted
+ * @throws StorageException if exception occurred during encryption
+ */
+ public void put(String key, String value, boolean encrypt) throws StorageException;
+
+ /**
+ * Retrieves a value associated with the key in this node. If the value was encrypted,
+ * it is decrypted.
+ * @param key key with this the value is associated
+ * @param def default value to return if the key is not associated with any value
+ * @return value associated the key. If value was stored in an encrypted form, it will be decrypted
+ * @throws StorageException if exception occurred during decryption
+ */
+ public String get(String key, String def) throws StorageException;
+
+ /**
+ * Removes value associated with the key.
+ * @param key key with which a value is associated
+ */
+ public void remove(String key);
+
+ /**
+ * Removes all values from this node.
+ */
+ public void clear();
+
+ /**
+ * Returns keys that have associated values.
+ * @return keys that have associated values
+ */
+ public String[] keys();
+
+ /**
+ * Returns names of children nodes
+ * @return names of children nodes
+ */
+ public String[] childrenNames();
+
+ /**
+ * Returns parent of this node
+ * @return parent of this node
+ */
+ public ISecurePreferences parent();
+
+ /**
+ * Returns node corresponding to the path specified. If such node does not
+ * exist, a new node is created.
+ * @see org.osgi.service.prefs.Preferences
+ * @see org.osgi.service.prefs.Preferences#node(String)
+ * @param pathName absolute or relative path to the node
+ * @return node corresponding to the path
+ */
+ public ISecurePreferences node(String pathName);
+
+ /**
+ * Checks if the node corresponding to the specified path exists in this tree
+ * of secure preferences.
+ * @see org.osgi.service.prefs.Preferences
+ * @see org.osgi.service.prefs.Preferences#node(String)
+ * @param pathName absolute or relative path to the node
+ * @return <code>true</code> if node corresponding to the path exists, <code>false</code> otherwise
+ */
+ public boolean nodeExists(String pathName);
+
+ /**
+ * Removes this node from the tree of secure preferences.
+ */
+ public void removeNode();
+
+ /**
+ * Returns name of this node.
+ * @return name of this node
+ */
+ public String name();
+
+ /**
+ * Returns absolute path to this node.
+ * @return absolute path to this node
+ */
+ public String absolutePath();
+
+ /**
+ * Saves the tree of secure preferences to the persistent storage. This method can be called
+ * on any node in the secure preference tree.
+ * @throws IOException if error occurred while saving secure preferences
+ */
+ public void flush() throws IOException;
+
+ /**
+ * Stores a value associated with the key in this node.
+ * @param key key with which the value is going to be associated
+ * @param value value to store
+ * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value
+ * does not need to be encrypted
+ * @throws StorageException if exception occurred during encryption
+ */
+ public void putInt(String key, int value, boolean encrypt) throws StorageException;
+
+ /**
+ * Retrieves a value associated with the key in this node. If the value was encrypted,
+ * it is decrypted.
+ * @param key key with this the value is associated
+ * @param def default value to return if the key is not associated with any value
+ * @return value associated the key. If value was stored in an encrypted form, it will be decrypted
+ * @throws StorageException if exception occurred during decryption
+ */
+ public int getInt(String key, int def) throws StorageException;
+
+ /**
+ * Stores a value associated with the key in this node.
+ * @param key key with which the value is going to be associated
+ * @param value value to store
+ * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value
+ * does not need to be encrypted
+ * @throws StorageException if exception occurred during encryption
+ */
+ public void putLong(String key, long value, boolean encrypt) throws StorageException;
+
+ /**
+ * Retrieves a value associated with the key in this node. If the value was encrypted,
+ * it is decrypted.
+ * @param key key with this the value is associated
+ * @param def default value to return if the key is not associated with any value
+ * @return value associated the key. If value was stored in an encrypted form, it will be decrypted
+ * @throws StorageException if exception occurred during decryption
+ */
+ public long getLong(String key, long def) throws StorageException;
+
+ /**
+ * Stores a value associated with the key in this node.
+ * @param key key with which the value is going to be associated
+ * @param value value to store
+ * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value
+ * does not need to be encrypted
+ * @throws StorageException if exception occurred during encryption
+ */
+ public void putBoolean(String key, boolean value, boolean encrypt) throws StorageException;
+
+ /**
+ * Retrieves a value associated with the key in this node. If the value was encrypted,
+ * it is decrypted.
+ * @param key key with this the value is associated
+ * @param def default value to return if the key is not associated with any value
+ * @return value associated the key. If value was stored in an encrypted form, it will be decrypted
+ * @throws StorageException if exception occurred during decryption
+ */
+ public boolean getBoolean(String key, boolean def) throws StorageException;
+
+ /**
+ * Stores a value associated with the key in this node.
+ * @param key key with which the value is going to be associated
+ * @param value value to store
+ * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value
+ * does not need to be encrypted
+ * @throws StorageException if exception occurred during encryption
+ */
+ public void putFloat(String key, float value, boolean encrypt) throws StorageException;
+
+ /**
+ * Retrieves a value associated with the key in this node. If the value was encrypted,
+ * it is decrypted.
+ * @param key key with this the value is associated
+ * @param def default value to return if the key is not associated with any value
+ * @return value associated the key. If value was stored in an encrypted form, it will be decrypted
+ * @throws StorageException if exception occurred during decryption
+ */
+ public float getFloat(String key, float def) throws StorageException;
+
+ /**
+ * Stores a value associated with the key in this node.
+ * @param key key with which the value is going to be associated
+ * @param value value to store
+ * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value
+ * does not need to be encrypted
+ * @throws StorageException if exception occurred during encryption
+ */
+ public void putDouble(String key, double value, boolean encrypt) throws StorageException;
+
+ /**
+ * Retrieves a value associated with the key in this node. If the value was encrypted,
+ * it is decrypted.
+ * @param key key with this the value is associated
+ * @param def default value to return if the key is not associated with any value
+ * @return value associated the key. If value was stored in an encrypted form, it will be decrypted
+ * @throws StorageException if exception occurred during decryption
+ */
+ public double getDouble(String key, double def) throws StorageException;
+
+ /**
+ * Stores a value associated with the key in this node.
+ * @param key key with which the value is going to be associated
+ * @param value value to store
+ * @param encrypt <code>true</code> if value is to be encrypted, <code>false</code> value
+ * does not need to be encrypted
+ * @throws StorageException if exception occurred during encryption
+ */
+ public void putByteArray(String key, byte[] value, boolean encrypt) throws StorageException;
+
+ /**
+ * Retrieves a value associated with the key in this node. If the value was encrypted,
+ * it is decrypted.
+ * @param key key with this the value is associated
+ * @param def default value to return if the key is not associated with any value
+ * @return value associated the key. If value was stored in an encrypted form, it will be decrypted
+ * @throws StorageException if exception occurred during decryption
+ */
+ public byte[] getByteArray(String key, byte[] def) throws StorageException;
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/SecurePreferencesFactory.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/SecurePreferencesFactory.java
new file mode 100644
index 0000000..20decf2
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/SecurePreferencesFactory.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.storage;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Map;
+import org.eclipse.equinox.internal.security.auth.AuthPlugin;
+import org.eclipse.equinox.internal.security.auth.nls.SecAuthMessages;
+import org.eclipse.equinox.internal.security.storage.SecurePreferencesMapper;
+import org.eclipse.equinox.security.storage.provider.IProviderHints;
+
+/**
+ * Use this class to access to secure preferences. Secure preferences allow storage of
+ * data in an encrypted form.
+ * <p>
+ * This class is not intended to be instantiated or extended by clients.
+ * </p>
+ */
+final public class SecurePreferencesFactory {
+
+ static private ISecurePreferences defaultPreferences = null;
+
+ /**
+ * Returns default secure preferences.
+ * <p>
+ * The framework will attempt to open secure preferences in a user-specific location
+ * so that information stored can be shared among all programs run by the user.
+ * The location is determined as follows:
+ * <ul>
+ * <li> Java's "user.home" environment variable. On Windows system it usually
+ * corresponds to the %USERPROFILE% environment variable or determined as the parent of
+ * user's desktop folder. On Unix Java usually determines it from user's entry
+ * in the password file (commonly this corresponds to $HOME environment variable);</li>
+ * <li> if it fails, preferences will use configuration location of the current Eclipse
+ * instance.</li>
+ * </ul>
+ * </p>
+ * @return default instance of secure preferences, <code>null</code> if application
+ * was unable to create secure preferences using default location
+ */
+ static public ISecurePreferences getDefault() {
+ if (defaultPreferences == null) {
+ try {
+ defaultPreferences = open(null, null);
+ } catch (IOException e) {
+ AuthPlugin.getDefault().logError(SecAuthMessages.keyringNotAvailable, e);
+ }
+ }
+ return defaultPreferences;
+ }
+
+ /**
+ * Returns a secure properties corresponding to the URL locations supplied. If URL
+ * is <code>null</code>, a default location is used.
+ * <p>
+ * Note that while this method accepts URLs to account for future expandability of this API,
+ * at present the method only accepts "file" URLs that point to a directory.
+ * An {@link IOException} might be thrown if unsupported URL is passed to this method.
+ * </p><p>
+ * Similarly to the rest of the Equinox, URLs passed as an argument must not be encoded,
+ * meaning that spaces should stay as spaces, not as "%x20".
+ * </p>
+ * @param location URL pointing to the location of secure storage. At present only file URLs
+ * are supported. Pass <code>null</code> to use default location
+ * @param options use to pass hints to the secure preferences implementation. Pass <code>null</code>
+ * if no options are needed. See {@link IProviderHints}
+ * @return a secure preferences
+ * @throws IOException if unsupported URLs types are passed in, or if location is not accessible
+ */
+ static public ISecurePreferences open(URL location, Map options) throws IOException {
+ return SecurePreferencesMapper.open(location, options);
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/StorageException.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/StorageException.java
new file mode 100644
index 0000000..162e3df
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/StorageException.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.storage;
+
+/**
+ * This class describes an exception that could be produced by the secure
+ * preferences. Depending on the error code, callers might be able to mitigate
+ * the originating problems and re-try the operation (for instance, if incorrect
+ * password was provided or in case a required storage module was not available).
+ * <p>
+ * This class is not intended to be instantiated or extended by clients.
+ * </p>
+ */
+final public class StorageException extends Exception {
+
+ private static final long serialVersionUID = -6352767405585664435L;
+
+ /**
+ * Internal error due to a problem in setup or internal implementation.
+ */
+ final public static int INTERNAL_ERROR = 0;
+
+ /**
+ * No appropriate password provider module is available.
+ */
+ final public static int NO_SECURE_MODULE = 1;
+
+ /**
+ * Error occurred during the encryption process.
+ * <p>
+ * Such error might have being created by using inappropriate key, for instance, using key
+ * that is too strong for the cryptographic policy in JVM.
+ * </p>
+ */
+ final public static int ENCRYPTION_ERROR = 2;
+
+ /**
+ * Error occurred during the decryption process.
+ * <p>
+ * This error might be caused by an incorrect password or corrupted data.
+ * </p>
+ */
+ final public static int DECRYPTION_ERROR = 3;
+
+ /**
+ * Secure preferences were unable to retrieve the password.
+ */
+ final public static int NO_PASSWORD = 4;
+
+ final private int errorCode;
+
+ public StorageException(int errorCode, Throwable exception) {
+ super(exception.getMessage(), exception);
+ this.errorCode = errorCode;
+ }
+
+ public StorageException(int errorCode, String message) {
+ super(message);
+ this.errorCode = errorCode;
+ }
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/provider/IPreferencesContainer.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/provider/IPreferencesContainer.java
new file mode 100644
index 0000000..51dca5c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/provider/IPreferencesContainer.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.storage.provider;
+
+import java.net.URL;
+import org.eclipse.equinox.security.storage.ISecurePreferences;
+import org.eclipse.equinox.security.storage.SecurePreferencesFactory;
+
+/**
+ * The container of the secure preferences. Objects implementing this
+ * interface are supplied to to various provider method calls to
+ * describe current context.
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ * @see IPasswordProvider
+ */
+public interface IPreferencesContainer {
+
+ /**
+ * Returns location corresponding to the secure preferences.
+ * @return location corresponding to the secure preferences
+ */
+ public URL getLocation();
+
+ /**
+ * Returns secure preferences contained in this container.
+ * @return root node of the secure preferences contained in this container
+ */
+ public ISecurePreferences getPreferences();
+
+ /**
+ * Determines is a given option is specified for this container.
+ * @see SecurePreferencesFactory#open(java.net.URL, java.util.Map)
+ * @see IProviderHints
+ * @param key key describing the option
+ * @return <code>true</code> if container has this option; <code>false</code> otehrwise
+ */
+ public boolean hasOption(Object key);
+
+ /**
+ * Returns an option specified for this container, or <code>null</code>
+ * if the option was not specified.
+ * @param key describes the option
+ * @return value of the option for this container, or <code>null</code>
+ * the option was not specified
+ */
+ public Object getOption(Object key);
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/provider/IProviderHints.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/provider/IProviderHints.java
new file mode 100644
index 0000000..e401ac0
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/provider/IProviderHints.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.storage.provider;
+
+import javax.crypto.spec.PBEKeySpec;
+import org.eclipse.equinox.security.storage.SecurePreferencesFactory;
+
+/**
+ * Sometimes it might be desirable to pass some context information to the password
+ * provider modules (such as a need to run without UI prompts). Below are some pre-defined
+ * options that can be used to exchange information between creators of secure storage
+ * and password providers.
+ * <p>
+ * Options can be specified as an entry in the options map
+ * {@link SecurePreferencesFactory#open(java.net.URL, java.util.Map)}.
+ * </p><p>
+ * Password provider modules are advised to take into consideration those options when
+ * applicable; note, however, that it is up to specific module to decide if (and how)
+ * they would respond to an option.
+ * </p><p>
+ * The set of options is open-ended and not limited to options specified below; modules can
+ * choose to process additional hints.
+ * </p><p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ */
+public interface IProviderHints {
+
+ /**
+ * Specifies the required password provider module to be used with the storage. Expected value: {@link String}.
+ */
+ static final public String REQUIRED_MODULE_ID = "org.eclipse.equinox.security.storage.requiredID"; //$NON-NLS-1$
+
+ /**
+ * Specifies if it is possible to prompt user. Expected value: {@link Boolean}.
+ */
+ static final public String PROMPT_USER = "org.eclipse.equinox.security.storage.promptUser"; //$NON-NLS-1$
+
+ /**
+ * Storage will use this password. Expected value: {@link PBEKeySpec}.
+ */
+ static final public String DEFAULT_PASSWORD = "org.eclipse.equinox.security.storage.defaultPassword"; //$NON-NLS-1$
+
+ /**
+ * Specifies if a new password is being requested. Expected value: {@link Boolean}.
+ */
+ static final public String NEW_PASSWORD = "org.eclipse.equinox.security.storage.newPassword"; //$NON-NLS-1$
+
+}
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/provider/PasswordProvider.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/provider/PasswordProvider.java
new file mode 100644
index 0000000..27ed5d6
--- /dev/null
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/security/storage/provider/PasswordProvider.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.security.storage.provider;
+
+import javax.crypto.spec.PBEKeySpec;
+
+/**
+ * Password provider modules should extend this class. Secure storage will
+ * ask modules for passwords used to encrypt entries stored in the secure preferences.
+ * <p>
+ * Password provider modules can be through of as trusted 3rd parties used
+ * to provide passwords to open keyrings containing secure preferences.
+ * </p><p>
+ * Use org.eclipse.equinox.security.secureStorage extension point to contribute
+ * password provider module to the secure storage system.
+ * </p>
+ */
+abstract public class PasswordProvider {
+
+ /**
+ * This method should return the password used to encrypt entries in the secure
+ * preferences.
+ * @param container container of the secure preferences
+ * @return password used to encrypt entries in the secure preferences, <code>null</code>
+ * if unable to obtain password
+ */
+ abstract public PBEKeySpec login(IPreferencesContainer container);
+
+ /**
+ * A logical equivalent of "logout" for the password providers.
+ * <p>
+ * The module should clear its cached password if it is the password that can be
+ * re-obtained from some third party (such as asking user to type it in). Modules
+ * should not discard auto generated passwords that are not available from other
+ * sources.
+ * </p>
+ * @param container container of the secure preferences
+ */
+ abstract public void logout(IPreferencesContainer container);
+
+ /**
+ * Constructor.
+ */
+ public PasswordProvider() {
+ // placeholder
+ }
+
+ /**
+ * The framework might call this method if it suspects that the password is invalid
+ * (for instance, due to a failed data decryption).
+ * @param e exception that occurred in the secure preferences processing
+ * @param container container of the secure preferences
+ * @return <code>true</code> if a different password might be provided; <code>false</code>
+ * otherwise. If in doubt, return <code>false</code>
+ */
+ public boolean changePassword(Exception e, IPreferencesContainer container) {
+ return false;
+ }
+
+}