From fb6196708160e06a2215abfeb55a4773e3223fb3 Mon Sep 17 00:00:00 2001 From: Dave Borowitz Date: Fri, 20 Jan 2012 14:05:59 -0800 Subject: Extract OpenID RPC implementation into its own module This avoids a dependency on openid4java for users that don't need OpenID support. Change-Id: I8dfce1e32f145aebed5e6c1d01c77872528ab43f --- gerrit-openid/.gitignore | 5 + .../.settings/org.eclipse.core.resources.prefs | 5 + .../.settings/org.eclipse.core.runtime.prefs | 3 + gerrit-openid/.settings/org.eclipse.jdt.core.prefs | 269 ++++++++++ gerrit-openid/.settings/org.eclipse.jdt.ui.prefs | 61 +++ gerrit-openid/pom.xml | 91 ++++ .../httpd/auth/openid/OpenIdLoginServlet.java | 57 +++ .../gerrit/httpd/auth/openid/OpenIdModule.java | 35 ++ .../httpd/auth/openid/OpenIdServiceImpl.java | 554 +++++++++++++++++++++ .../gerrit/httpd/auth/openid/XrdsFilter.java | 42 ++ .../gerrit/httpd/auth/openid/XrdsServlet.java | 72 +++ 11 files changed, 1194 insertions(+) create mode 100644 gerrit-openid/.gitignore create mode 100644 gerrit-openid/.settings/org.eclipse.core.resources.prefs create mode 100644 gerrit-openid/.settings/org.eclipse.core.runtime.prefs create mode 100644 gerrit-openid/.settings/org.eclipse.jdt.core.prefs create mode 100644 gerrit-openid/.settings/org.eclipse.jdt.ui.prefs create mode 100644 gerrit-openid/pom.xml create mode 100644 gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdLoginServlet.java create mode 100644 gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdModule.java create mode 100644 gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java create mode 100644 gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/XrdsFilter.java create mode 100644 gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/XrdsServlet.java (limited to 'gerrit-openid') diff --git a/gerrit-openid/.gitignore b/gerrit-openid/.gitignore new file mode 100644 index 0000000000..194bedcbc4 --- /dev/null +++ b/gerrit-openid/.gitignore @@ -0,0 +1,5 @@ +/target +/.classpath +/.project +/.settings/org.maven.ide.eclipse.prefs +/.settings/org.eclipse.m2e.core.prefs \ No newline at end of file diff --git a/gerrit-openid/.settings/org.eclipse.core.resources.prefs b/gerrit-openid/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..fc11c3fe6f --- /dev/null +++ b/gerrit-openid/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +#Thu Jul 28 11:02:36 PDT 2011 +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/test/java=UTF-8 +encoding/=UTF-8 diff --git a/gerrit-openid/.settings/org.eclipse.core.runtime.prefs b/gerrit-openid/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 0000000000..8667cfd4a3 --- /dev/null +++ b/gerrit-openid/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,3 @@ +#Tue Sep 02 16:59:24 PDT 2008 +eclipse.preferences.version=1 +line.separator=\n diff --git a/gerrit-openid/.settings/org.eclipse.jdt.core.prefs b/gerrit-openid/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..470942d4f6 --- /dev/null +++ b/gerrit-openid/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,269 @@ +#Thu Jul 28 11:02:36 PDT 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +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.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 +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=16 +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=16 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16 +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=0 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=0 +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=2 +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=true +org.eclipse.jdt.core.formatter.comment.format_header=true +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +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=true +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_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not 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=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=do not 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=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not 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=true +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=80 +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=3 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=2 +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true diff --git a/gerrit-openid/.settings/org.eclipse.jdt.ui.prefs b/gerrit-openid/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000000..d4218a5fc0 --- /dev/null +++ b/gerrit-openid/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,61 @@ +#Wed Jul 29 11:31:38 PDT 2009 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Google Format +formatter_settings_version=11 +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=com.google;com;junit;net;org;java;javax; +org.eclipse.jdt.ui.ondemandthreshold=99 +org.eclipse.jdt.ui.staticondemandthreshold=99 +org.eclipse.jdt.ui.text.custom_code_templates= +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=false +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=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.make_local_variable_final=true +sp_cleanup.make_parameters_final=true +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=false +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=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +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/gerrit-openid/pom.xml b/gerrit-openid/pom.xml new file mode 100644 index 0000000000..310bd1aebd --- /dev/null +++ b/gerrit-openid/pom.xml @@ -0,0 +1,91 @@ + + + + 4.0.0 + + + com.google.gerrit + gerrit-parent + 2.2-SNAPSHOT + + + gerrit-openid + Gerrit Code Review - OpenID servlet and RPC + + + OpenID + + + + + org.apache.tomcat + servlet-api + provided + + + + com.google.code.findbugs + jsr305 + + + + org.eclipse.jgit + org.eclipse.jgit.http.server + + + + com.google.gwt + gwt-servlet + + + + org.openid4java + openid4java-consumer + pom + + + + com.google.gerrit + gerrit-httpd + ${project.version} + + + + com.google.gerrit + gerrit-server + ${project.version} + + + + + + + org.apache.maven.plugins + maven-source-plugin + + + + jar + + + + + + + diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdLoginServlet.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdLoginServlet.java new file mode 100644 index 0000000000..cfb767d0ba --- /dev/null +++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdLoginServlet.java @@ -0,0 +1,57 @@ +// Copyright (C) 2008 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.httpd.auth.openid; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import java.io.IOException; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** Handles the /OpenID URL for web based single-sign-on. */ +@SuppressWarnings("serial") +@Singleton +class OpenIdLoginServlet extends HttpServlet { + private final OpenIdServiceImpl impl; + + @Inject + OpenIdLoginServlet(final OpenIdServiceImpl i) { + impl = i; + } + + @Override + public void doGet(final HttpServletRequest req, final HttpServletResponse rsp) + throws IOException { + doPost(req, rsp); + } + + @Override + public void doPost(final HttpServletRequest req, final HttpServletResponse rsp) + throws IOException { + try { + rsp.setHeader("Expires", "Fri, 01 Jan 1980 00:00:00 GMT"); + rsp.setHeader("Pragma", "no-cache"); + rsp.setHeader("Cache-Control", "no-cache, must-revalidate"); + impl.doAuth(req, rsp); + } catch (Exception e) { + getServletContext().log("Unexpected error during authentication", e); + rsp.reset(); + rsp.sendError(500); + } + } +} diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdModule.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdModule.java new file mode 100644 index 0000000000..a928cb8536 --- /dev/null +++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdModule.java @@ -0,0 +1,35 @@ +// Copyright (C) 2009 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.httpd.auth.openid; + +import com.google.gerrit.httpd.rpc.RpcServletModule; +import com.google.inject.servlet.ServletModule; + +/** Servlets and RPC support related to OpenID authentication. */ +public class OpenIdModule extends ServletModule { + @Override + protected void configureServlets() { + serve("/" + OpenIdServiceImpl.RETURN_URL).with(OpenIdLoginServlet.class); + serve("/" + XrdsServlet.LOCATION).with(XrdsServlet.class); + filter("/").through(XrdsFilter.class); + + install(new RpcServletModule(RpcServletModule.PREFIX) { + @Override + protected void configureServlets() { + rpc(OpenIdServiceImpl.class); + } + }); + } +} diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java new file mode 100644 index 0000000000..02ef7657e2 --- /dev/null +++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java @@ -0,0 +1,554 @@ +// Copyright (C) 2009 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.httpd.auth.openid; + +import com.google.gerrit.common.PageLinks; +import com.google.gerrit.common.auth.SignInMode; +import com.google.gerrit.common.auth.openid.DiscoveryResult; +import com.google.gerrit.common.auth.openid.OpenIdProviderPattern; +import com.google.gerrit.common.auth.openid.OpenIdService; +import com.google.gerrit.common.auth.openid.OpenIdUrls; +import com.google.gerrit.httpd.WebSession; +import com.google.gerrit.reviewdb.Account; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.UrlEncoded; +import com.google.gerrit.server.account.AccountException; +import com.google.gerrit.server.account.AccountManager; +import com.google.gerrit.server.config.AuthConfig; +import com.google.gerrit.server.config.CanonicalWebUrl; +import com.google.gerrit.server.config.ConfigUtil; +import com.google.gerrit.server.config.GerritServerConfig; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwtorm.client.KeyUtil; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import org.eclipse.jgit.lib.Config; +import org.openid4java.consumer.ConsumerException; +import org.openid4java.consumer.ConsumerManager; +import org.openid4java.consumer.VerificationResult; +import org.openid4java.discovery.DiscoveryException; +import org.openid4java.discovery.DiscoveryInformation; +import org.openid4java.message.AuthRequest; +import org.openid4java.message.Message; +import org.openid4java.message.MessageException; +import org.openid4java.message.MessageExtension; +import org.openid4java.message.ParameterList; +import org.openid4java.message.ax.AxMessage; +import org.openid4java.message.ax.FetchRequest; +import org.openid4java.message.ax.FetchResponse; +import org.openid4java.message.pape.PapeMessage; +import org.openid4java.message.pape.PapeRequest; +import org.openid4java.message.pape.PapeResponse; +import org.openid4java.message.sreg.SRegMessage; +import org.openid4java.message.sreg.SRegRequest; +import org.openid4java.message.sreg.SRegResponse; +import org.openid4java.util.HttpClientFactory; +import org.openid4java.util.ProxyProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nullable; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Singleton +class OpenIdServiceImpl implements OpenIdService { + private static final Logger log = + LoggerFactory.getLogger(OpenIdServiceImpl.class); + + static final String RETURN_URL = "OpenID"; + + private static final String P_MODE = "gerrit.mode"; + private static final String P_TOKEN = "gerrit.token"; + private static final String P_REMEMBER = "gerrit.remember"; + private static final String P_CLAIMED = "gerrit.claimed"; + private static final int LASTID_AGE = 365 * 24 * 60 * 60; // seconds + + private static final String OPENID_MODE = "openid.mode"; + private static final String OMODE_CANCEL = "cancel"; + + private static final String SCHEMA_EMAIL = + "http://schema.openid.net/contact/email"; + private static final String SCHEMA_FIRSTNAME = + "http://schema.openid.net/namePerson/first"; + private static final String SCHEMA_LASTNAME = + "http://schema.openid.net/namePerson/last"; + + private final Provider webSession; + private final Provider identifiedUser; + private final Provider urlProvider; + private final AccountManager accountManager; + private final ConsumerManager manager; + private final List allowedOpenIDs; + + /** Maximum age, in seconds, before forcing re-authentication of account. */ + private final int papeMaxAuthAge; + + @Inject + OpenIdServiceImpl(final Provider cf, + final Provider iu, + @CanonicalWebUrl @Nullable final Provider up, + @GerritServerConfig final Config config, final AuthConfig ac, + final AccountManager am) throws ConsumerException, MalformedURLException { + + if (config.getString("http", null, "proxy") != null) { + final URL proxyUrl = new URL(config.getString("http", null, "proxy")); + String username = config.getString("http", null, "proxyUsername"); + String password = config.getString("http", null, "proxyPassword"); + + final String userInfo = proxyUrl.getUserInfo(); + if (userInfo != null) { + int c = userInfo.indexOf(':'); + if (0 < c) { + username = userInfo.substring(0, c); + password = userInfo.substring(c + 1); + } else { + username = userInfo; + } + } + + final ProxyProperties proxy = new ProxyProperties(); + proxy.setProxyHostName(proxyUrl.getHost()); + proxy.setProxyPort(proxyUrl.getPort()); + proxy.setUserName(username); + proxy.setPassword(password); + HttpClientFactory.setProxyProperties(proxy); + } + + webSession = cf; + identifiedUser = iu; + urlProvider = up; + accountManager = am; + manager = new ConsumerManager(); + allowedOpenIDs = ac.getAllowedOpenIDs(); + papeMaxAuthAge = (int) ConfigUtil.getTimeUnit(config, // + "auth", null, "maxOpenIdSessionAge", -1, TimeUnit.SECONDS); + } + + @SuppressWarnings("unchecked") + public void discover(final String openidIdentifier, final SignInMode mode, + final boolean remember, final String returnToken, + final AsyncCallback cb) { + if (!isAllowedOpenID(openidIdentifier)) { + cb.onSuccess(new DiscoveryResult(DiscoveryResult.Status.NOT_ALLOWED)); + return; + } + + final State state; + state = init(openidIdentifier, mode, remember, returnToken); + if (state == null) { + cb.onSuccess(new DiscoveryResult(DiscoveryResult.Status.NO_PROVIDER)); + return; + } + + final AuthRequest aReq; + try { + aReq = manager.authenticate(state.discovered, state.retTo.toString()); + aReq.setRealm(state.contextUrl); + + if (requestRegistration(aReq)) { + final SRegRequest sregReq = SRegRequest.createFetchRequest(); + sregReq.addAttribute("fullname", true); + sregReq.addAttribute("email", true); + aReq.addExtension(sregReq); + + final FetchRequest fetch = FetchRequest.createFetchRequest(); + fetch.addAttribute("FirstName", SCHEMA_FIRSTNAME, true); + fetch.addAttribute("LastName", SCHEMA_LASTNAME, true); + fetch.addAttribute("Email", SCHEMA_EMAIL, true); + aReq.addExtension(fetch); + } + + if (0 <= papeMaxAuthAge) { + final PapeRequest pape = PapeRequest.createPapeRequest(); + pape.setMaxAuthAge(papeMaxAuthAge); + aReq.addExtension(pape); + } + } catch (MessageException e) { + log.error("Cannot create OpenID redirect for " + openidIdentifier, e); + cb.onSuccess(new DiscoveryResult(DiscoveryResult.Status.ERROR)); + return; + } catch (ConsumerException e) { + log.error("Cannot create OpenID redirect for " + openidIdentifier, e); + cb.onSuccess(new DiscoveryResult(DiscoveryResult.Status.ERROR)); + return; + } + + cb.onSuccess(new DiscoveryResult(aReq.getDestinationUrl(false), // + aReq.getParameterMap())); + } + + private boolean requestRegistration(final AuthRequest aReq) { + if (AuthRequest.SELECT_ID.equals(aReq.getIdentity())) { + // We don't know anything about the identity, as the provider + // will offer the user a way to indicate their identity. Skip + // any database query operation and assume we must ask for the + // registration information, in case the identity is new to us. + // + return true; + + } + + // We might already have this account on file. Look for it. + // + try { + return accountManager.lookup(aReq.getIdentity()) == null; + } catch (AccountException e) { + log.warn("Cannot determine if user account exists", e); + return true; + } + } + + /** Called by {@link OpenIdLoginServlet} doGet, doPost */ + void doAuth(final HttpServletRequest req, final HttpServletResponse rsp) + throws Exception { + if (OMODE_CANCEL.equals(req.getParameter(OPENID_MODE))) { + cancel(req, rsp); + return; + } + + // Process the authentication response. + // + final SignInMode mode = signInMode(req); + final String openidIdentifier = req.getParameter("openid.identity"); + final String claimedIdentifier = req.getParameter(P_CLAIMED); + final String returnToken = req.getParameter(P_TOKEN); + final boolean remember = "1".equals(req.getParameter(P_REMEMBER)); + final String rediscoverIdentifier = + claimedIdentifier != null ? claimedIdentifier : openidIdentifier; + final State state; + + if (!isAllowedOpenID(rediscoverIdentifier) + || !isAllowedOpenID(openidIdentifier) + || (claimedIdentifier != null && !isAllowedOpenID(claimedIdentifier))) { + cancelWithError(req, rsp, "Provider not allowed"); + return; + } + + state = init(rediscoverIdentifier, mode, remember, returnToken); + if (state == null) { + // Re-discovery must have failed, we can't run a login. + // + cancel(req, rsp); + return; + } + + final String returnTo = req.getParameter("openid.return_to"); + if (returnTo != null && returnTo.contains("openid.rpnonce=")) { + // Some providers (claimid.com) seem to embed these request + // parameters into our return_to URL, and then give us them + // in the return_to request parameter. But not all. + // + state.retTo.put("openid.rpnonce", req.getParameter("openid.rpnonce")); + state.retTo.put("openid.rpsig", req.getParameter("openid.rpsig")); + } + + final VerificationResult result = + manager.verify(state.retTo.toString(), new ParameterList(req + .getParameterMap()), state.discovered); + if (result.getVerifiedId() == null /* authentication failure */) { + if ("Nonce verification failed.".equals(result.getStatusMsg())) { + // We might be suffering from clock skew on this system. + // + log.error("OpenID failure: " + result.getStatusMsg() + + " Likely caused by clock skew on this server," + + " install/configure NTP."); + cancelWithError(req, rsp, result.getStatusMsg()); + + } else if (result.getStatusMsg() != null) { + // Authentication failed. + // + log.error("OpenID failure: " + result.getStatusMsg()); + cancelWithError(req, rsp, result.getStatusMsg()); + + } else { + // Assume authentication was canceled. + // + cancel(req, rsp); + } + return; + } + + final Message authRsp = result.getAuthResponse(); + SRegResponse sregRsp = null; + FetchResponse fetchRsp = null; + + if (0 <= papeMaxAuthAge) { + PapeResponse ext; + boolean unsupported = false; + + try { + ext = (PapeResponse) authRsp.getExtension(PapeMessage.OPENID_NS_PAPE); + } catch (MessageException err) { + // Far too many providers are unable to provide PAPE extensions + // right now. Instead of blocking all of them log the error and + // let the authentication complete anyway. + // + log.error("Invalid PAPE response " + openidIdentifier + ": " + err); + unsupported = true; + ext = null; + } + if (!unsupported && ext == null) { + log.error("No PAPE extension response from " + openidIdentifier); + cancelWithError(req, rsp, "OpenID provider does not support PAPE."); + return; + } + } + + if (authRsp.hasExtension(SRegMessage.OPENID_NS_SREG)) { + final MessageExtension ext = + authRsp.getExtension(SRegMessage.OPENID_NS_SREG); + if (ext instanceof SRegResponse) { + sregRsp = (SRegResponse) ext; + } + } + + if (authRsp.hasExtension(AxMessage.OPENID_NS_AX)) { + final MessageExtension ext = authRsp.getExtension(AxMessage.OPENID_NS_AX); + if (ext instanceof FetchResponse) { + fetchRsp = (FetchResponse) ext; + } + } + + final com.google.gerrit.server.account.AuthRequest areq = + new com.google.gerrit.server.account.AuthRequest(openidIdentifier); + + if (sregRsp != null) { + areq.setDisplayName(sregRsp.getAttributeValue("fullname")); + areq.setEmailAddress(sregRsp.getAttributeValue("email")); + + } else if (fetchRsp != null) { + final String firstName = fetchRsp.getAttributeValue("FirstName"); + final String lastName = fetchRsp.getAttributeValue("LastName"); + final StringBuilder n = new StringBuilder(); + if (firstName != null && firstName.length() > 0) { + n.append(firstName); + } + if (lastName != null && lastName.length() > 0) { + if (n.length() > 0) { + n.append(' '); + } + n.append(lastName); + } + areq.setDisplayName(n.length() > 0 ? n.toString() : null); + areq.setEmailAddress(fetchRsp.getAttributeValue("Email")); + } + + if (claimedIdentifier != null) { + // The user used a claimed identity which has delegated to the verified + // identity we have in our AuthRequest above. We still should have a + // link between the two, so set one up if not present. + // + Account.Id claimedId = accountManager.lookup(claimedIdentifier); + Account.Id actualId = accountManager.lookup(areq.getExternalId()); + + if (claimedId != null && actualId != null) { + if (claimedId.equals(actualId)) { + // Both link to the same account, that's what we expected. + } else { + // This is (for now) a fatal error. There are two records + // for what might be the same user. + // + log.error("OpenID accounts disagree over user identity:\n" + + " Claimed ID: " + claimedId + " is " + claimedIdentifier + + "\n" + " Delgate ID: " + actualId + " is " + + areq.getExternalId()); + cancelWithError(req, rsp, "Contact site administrator"); + return; + } + + } else if (claimedId == null && actualId != null) { + // Older account, the actual was already created but the claimed + // was missing due to a bug in Gerrit. Link the claimed. + // + final com.google.gerrit.server.account.AuthRequest linkReq = + new com.google.gerrit.server.account.AuthRequest(claimedIdentifier); + linkReq.setDisplayName(areq.getDisplayName()); + linkReq.setEmailAddress(areq.getEmailAddress()); + accountManager.link(actualId, linkReq); + + } else if (claimedId != null && actualId == null) { + // Claimed account already exists, but it smells like the user has + // changed their delegate to point to a different provider. Link + // the new provider. + // + accountManager.link(claimedId, areq); + + } else { + // Both are null, we are going to create a new account below. + } + } + + try { + final com.google.gerrit.server.account.AuthResult arsp; + switch (mode) { + case REGISTER: + case SIGN_IN: + arsp = accountManager.authenticate(areq); + + final Cookie lastId = new Cookie(OpenIdUrls.LASTID_COOKIE, ""); + lastId.setPath(req.getContextPath() + "/"); + if (remember) { + lastId.setValue(rediscoverIdentifier); + lastId.setMaxAge(LASTID_AGE); + } else { + lastId.setMaxAge(0); + } + rsp.addCookie(lastId); + webSession.get().login(arsp, remember); + if (arsp.isNew() && claimedIdentifier != null) { + final com.google.gerrit.server.account.AuthRequest linkReq = + new com.google.gerrit.server.account.AuthRequest( + claimedIdentifier); + linkReq.setDisplayName(areq.getDisplayName()); + linkReq.setEmailAddress(areq.getEmailAddress()); + accountManager.link(arsp.getAccountId(), linkReq); + } + callback(arsp.isNew(), req, rsp); + break; + + case LINK_IDENTIY: { + arsp = accountManager.link(identifiedUser.get().getAccountId(), areq); + webSession.get().login(arsp, remember); + callback(false, req, rsp); + break; + } + } + } catch (AccountException e) { + log.error("OpenID authentication failure", e); + cancelWithError(req, rsp, "Contact site administrator"); + } + } + + private boolean isSignIn(final SignInMode mode) { + switch (mode) { + case SIGN_IN: + case REGISTER: + return true; + default: + return false; + } + } + + private static SignInMode signInMode(final HttpServletRequest req) { + try { + return SignInMode.valueOf(req.getParameter(P_MODE)); + } catch (RuntimeException e) { + return SignInMode.SIGN_IN; + } + } + + private void callback(final boolean isNew, final HttpServletRequest req, + final HttpServletResponse rsp) throws IOException { + String token = req.getParameter(P_TOKEN); + if (token == null || token.isEmpty() || token.startsWith("/SignInFailure,")) { + token = PageLinks.MINE; + } + + final StringBuilder rdr = new StringBuilder(); + rdr.append(urlProvider.get()); + rdr.append('#'); + if (isNew && !token.startsWith(PageLinks.REGISTER + "/")) { + rdr.append(PageLinks.REGISTER); + } + rdr.append(token); + rsp.sendRedirect(rdr.toString()); + } + + private void cancel(final HttpServletRequest req, + final HttpServletResponse rsp) throws IOException { + if (isSignIn(signInMode(req))) { + webSession.get().logout(); + } + callback(false, req, rsp); + } + + private void cancelWithError(final HttpServletRequest req, + final HttpServletResponse rsp, final String errorDetail) + throws IOException { + final SignInMode mode = signInMode(req); + if (isSignIn(mode)) { + webSession.get().logout(); + } + final StringBuilder rdr = new StringBuilder(); + rdr.append(urlProvider.get()); + rdr.append('#'); + rdr.append("SignInFailure"); + rdr.append(','); + rdr.append(mode.name()); + rdr.append(','); + rdr.append(errorDetail != null ? KeyUtil.encode(errorDetail) : ""); + rsp.sendRedirect(rdr.toString()); + } + + private State init(final String openidIdentifier, final SignInMode mode, + final boolean remember, final String returnToken) { + final List list; + try { + list = manager.discover(openidIdentifier); + } catch (DiscoveryException e) { + log.error("Cannot discover OpenID " + openidIdentifier, e); + return null; + } + if (list == null || list.isEmpty()) { + return null; + } + + final String contextUrl = urlProvider.get(); + final DiscoveryInformation discovered = manager.associate(list); + final UrlEncoded retTo = new UrlEncoded(contextUrl + RETURN_URL); + retTo.put(P_MODE, mode.name()); + if (returnToken != null && returnToken.length() > 0) { + retTo.put(P_TOKEN, returnToken); + } + if (remember) { + retTo.put(P_REMEMBER, "1"); + } + if (discovered.hasClaimedIdentifier()) { + retTo.put(P_CLAIMED, discovered.getClaimedIdentifier().getIdentifier()); + } + return new State(discovered, retTo, contextUrl); + } + + private boolean isAllowedOpenID(final String id) { + for (final OpenIdProviderPattern pattern : allowedOpenIDs) { + if (pattern.matches(id)) { + return true; + } + } + return false; + } + + private static class State { + final DiscoveryInformation discovered; + final UrlEncoded retTo; + final String contextUrl; + + State(final DiscoveryInformation d, final UrlEncoded r, final String c) { + discovered = d; + retTo = r; + contextUrl = c; + } + } +} diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/XrdsFilter.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/XrdsFilter.java new file mode 100644 index 0000000000..92230f687d --- /dev/null +++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/XrdsFilter.java @@ -0,0 +1,42 @@ +package com.google.gerrit.httpd.auth.openid; + +import com.google.gerrit.server.config.CanonicalWebUrl; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +@Singleton +class XrdsFilter implements Filter { + private final Provider url; + + @Inject + XrdsFilter(@CanonicalWebUrl final Provider url) { + this.url = url; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + HttpServletResponse rsp = (HttpServletResponse) response; + rsp.setHeader("X-XRDS-Location", url.get() + XrdsServlet.LOCATION); + chain.doFilter(request, response); + } + + @Override + public void init(FilterConfig config) { + } + + @Override + public void destroy() { + } +} diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/XrdsServlet.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/XrdsServlet.java new file mode 100644 index 0000000000..98ad11d4b9 --- /dev/null +++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/XrdsServlet.java @@ -0,0 +1,72 @@ +// Copyright (C) 2010 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.httpd.auth.openid; + +import com.google.gerrit.server.config.CanonicalWebUrl; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import java.io.IOException; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Singleton +class XrdsServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + private static final String ENC = "UTF-8"; + static final String LOCATION = "OpenID.XRDS"; + + private final Provider url; + + @Inject + XrdsServlet(@CanonicalWebUrl final Provider url) { + this.url = url; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse rsp) + throws IOException { + final StringBuilder r = new StringBuilder(); + r.append(""); + r.append(""); + r.append(""); + r.append(""); + r.append("http://specs.openid.net/auth/2.0/return_to"); + r.append("" + url.get() + OpenIdServiceImpl.RETURN_URL + ""); + r.append(""); + r.append(""); + r.append(""); + r.append("\n"); + + final byte[] raw = r.toString().getBytes(ENC); + rsp.setContentLength(raw.length); + rsp.setContentType("application/xrds+xml"); + rsp.setCharacterEncoding(ENC); + + final ServletOutputStream out = rsp.getOutputStream(); + try { + out.write(raw); + } finally { + out.close(); + } + } +} -- cgit v1.2.3