Mercurial > hg > nginx
comparison src/mail/ngx_mail_auth_http_module.c @ 9290:4538c1ffb0f8
Mail: added support for XOAUTH2 and OAUTHBEARER authentication.
This patch adds support for the OAUTHBEARER SASL mechanism as defined
by RFC 7628, as well as pre-RFC XOAUTH2 SASL mechanism. For both
mechanisms, the "Auth-User" header is set to the client identity
obtained from the initial SASL response sent by the client, and the
"Auth-Pass" header is set to the Bearer token itself.
The auth server may return the "Auth-Error-SASL" header, which is
passed to the client as an additional SASL challenge. It is expected
to contain mechanism-specific error details, base64-encoded. After
the client responds (with an empty SASL response for XAUTH2, or with
"AQ==" dummy response for OAUTHBEARER), the error message from the
"Auth-Status" header is sent.
Based on a patch by Rob Mueller.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 03 Jun 2024 18:03:11 +0300 |
parents | 46ecad404a29 |
children | 03cdd806c0f2 |
comparison
equal
deleted
inserted
replaced
9289:20017bff0de8 | 9290:4538c1ffb0f8 |
---|---|
51 ngx_str_t addr; | 51 ngx_str_t addr; |
52 ngx_str_t port; | 52 ngx_str_t port; |
53 ngx_str_t err; | 53 ngx_str_t err; |
54 ngx_str_t errmsg; | 54 ngx_str_t errmsg; |
55 ngx_str_t errcode; | 55 ngx_str_t errcode; |
56 ngx_str_t errsasl; | |
56 | 57 |
57 time_t sleep; | 58 time_t sleep; |
58 | 59 |
59 ngx_pool_t *pool; | 60 ngx_pool_t *pool; |
60 }; | 61 }; |
65 static void ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s, | 66 static void ngx_mail_auth_http_ignore_status_line(ngx_mail_session_t *s, |
66 ngx_mail_auth_http_ctx_t *ctx); | 67 ngx_mail_auth_http_ctx_t *ctx); |
67 static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s, | 68 static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s, |
68 ngx_mail_auth_http_ctx_t *ctx); | 69 ngx_mail_auth_http_ctx_t *ctx); |
69 static void ngx_mail_auth_sleep_handler(ngx_event_t *rev); | 70 static void ngx_mail_auth_sleep_handler(ngx_event_t *rev); |
71 static void ngx_mail_auth_send_error(ngx_mail_session_t *s); | |
70 static ngx_int_t ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s, | 72 static ngx_int_t ngx_mail_auth_http_parse_header_line(ngx_mail_session_t *s, |
71 ngx_mail_auth_http_ctx_t *ctx); | 73 ngx_mail_auth_http_ctx_t *ctx); |
72 static void ngx_mail_auth_http_block_read(ngx_event_t *rev); | 74 static void ngx_mail_auth_http_block_read(ngx_event_t *rev); |
73 static void ngx_mail_auth_http_dummy_handler(ngx_event_t *ev); | 75 static void ngx_mail_auth_http_dummy_handler(ngx_event_t *ev); |
74 static ngx_buf_t *ngx_mail_auth_http_create_request(ngx_mail_session_t *s, | 76 static ngx_buf_t *ngx_mail_auth_http_create_request(ngx_mail_session_t *s, |
150 ngx_string("plain"), | 152 ngx_string("plain"), |
151 ngx_string("plain"), | 153 ngx_string("plain"), |
152 ngx_string("apop"), | 154 ngx_string("apop"), |
153 ngx_string("cram-md5"), | 155 ngx_string("cram-md5"), |
154 ngx_string("external"), | 156 ngx_string("external"), |
157 ngx_string("xoauth2"), | |
158 ngx_string("oauthbearer"), | |
155 ngx_string("none") | 159 ngx_string("none") |
156 }; | 160 }; |
157 | 161 |
158 static ngx_str_t ngx_mail_smtp_errcode = ngx_string("535 5.7.0"); | 162 static ngx_str_t ngx_mail_smtp_errcode = ngx_string("535 5.7.0"); |
159 | 163 |
675 ctx->errcode.len); | 679 ctx->errcode.len); |
676 | 680 |
677 continue; | 681 continue; |
678 } | 682 } |
679 | 683 |
684 if (len == sizeof("Auth-Error-SASL") - 1 | |
685 && ngx_strncasecmp(ctx->header_name_start, | |
686 (u_char *) "Auth-Error-SASL", | |
687 sizeof("Auth-Error-SASL") - 1) | |
688 == 0) | |
689 { | |
690 if (s->auth_method != NGX_MAIL_AUTH_XOAUTH2 | |
691 && s->auth_method != NGX_MAIL_AUTH_OAUTHBEARER) | |
692 { | |
693 continue; | |
694 } | |
695 | |
696 len = ctx->header_end - ctx->header_start; | |
697 | |
698 if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) { | |
699 size = len + sizeof("334 " CRLF) - 1; | |
700 | |
701 } else { | |
702 size = len + sizeof("+ " CRLF) - 1; | |
703 } | |
704 | |
705 p = ngx_pnalloc(s->connection->pool, size); | |
706 if (p == NULL) { | |
707 ngx_close_connection(ctx->peer.connection); | |
708 ngx_destroy_pool(ctx->pool); | |
709 ngx_mail_session_internal_server_error(s); | |
710 return; | |
711 } | |
712 | |
713 ctx->errsasl.len = size; | |
714 ctx->errsasl.data = p; | |
715 | |
716 if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) { | |
717 *p++ = '3'; *p++ = '3'; *p++ = '4'; *p++ = ' '; | |
718 | |
719 } else { | |
720 *p++ = '+'; *p++ = ' '; | |
721 } | |
722 | |
723 p = ngx_cpymem(p, ctx->header_start, len); | |
724 *p++ = CR; *p = LF; | |
725 | |
726 continue; | |
727 } | |
728 | |
680 /* ignore other headers */ | 729 /* ignore other headers */ |
681 | 730 |
682 continue; | 731 continue; |
683 } | 732 } |
684 | 733 |
715 *p++ = ' '; | 764 *p++ = ' '; |
716 p = ngx_cpymem(p, ctx->errmsg.data, ctx->errmsg.len); | 765 p = ngx_cpymem(p, ctx->errmsg.data, ctx->errmsg.len); |
717 *p++ = CR; *p = LF; | 766 *p++ = CR; *p = LF; |
718 } | 767 } |
719 | 768 |
720 s->out = ctx->err; | 769 s->out = ctx->errsasl; |
770 s->auth_err = ctx->err; | |
721 timer = ctx->sleep; | 771 timer = ctx->sleep; |
722 | 772 |
723 ngx_destroy_pool(ctx->pool); | 773 ngx_destroy_pool(ctx->pool); |
724 | 774 |
725 if (timer == 0) { | 775 if (timer == 0) { |
726 s->quit = 1; | 776 s->auth_quit = 1; |
727 ngx_mail_send(s->connection->write); | 777 ngx_mail_auth_send_error(s); |
728 return; | 778 return; |
729 } | 779 } |
730 | 780 |
731 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000)); | 781 ngx_add_timer(s->connection->read, (ngx_msec_t) (timer * 1000)); |
732 | 782 |
856 | 906 |
857 | 907 |
858 static void | 908 static void |
859 ngx_mail_auth_sleep_handler(ngx_event_t *rev) | 909 ngx_mail_auth_sleep_handler(ngx_event_t *rev) |
860 { | 910 { |
861 ngx_connection_t *c; | 911 ngx_connection_t *c; |
862 ngx_mail_session_t *s; | 912 ngx_mail_session_t *s; |
863 ngx_mail_core_srv_conf_t *cscf; | |
864 | 913 |
865 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail auth sleep handler"); | 914 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail auth sleep handler"); |
866 | 915 |
867 c = rev->data; | 916 c = rev->data; |
868 s = c->data; | 917 s = c->data; |
875 s->auth_wait = 0; | 924 s->auth_wait = 0; |
876 ngx_mail_auth_http_init(s); | 925 ngx_mail_auth_http_init(s); |
877 return; | 926 return; |
878 } | 927 } |
879 | 928 |
880 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | 929 ngx_mail_auth_send_error(s); |
881 | |
882 rev->handler = cscf->protocol->auth_state; | |
883 | |
884 s->mail_state = 0; | |
885 s->auth_method = NGX_MAIL_AUTH_PLAIN; | |
886 s->tag.len = 0; | |
887 | |
888 c->log->action = "in auth state"; | |
889 | |
890 ngx_mail_send(c->write); | |
891 | |
892 if (c->destroyed) { | |
893 return; | |
894 } | |
895 | |
896 ngx_add_timer(rev, cscf->timeout); | |
897 | |
898 if (rev->ready) { | |
899 rev->handler(rev); | |
900 return; | |
901 } | |
902 | |
903 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
904 ngx_mail_close_connection(c); | |
905 } | |
906 | |
907 return; | 930 return; |
908 } | 931 } |
909 | 932 |
910 if (rev->active) { | 933 if (rev->active) { |
911 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | 934 if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
912 ngx_mail_close_connection(c); | 935 ngx_mail_close_connection(c); |
913 } | 936 } |
937 } | |
938 } | |
939 | |
940 | |
941 static void | |
942 ngx_mail_auth_send_error(ngx_mail_session_t *s) | |
943 { | |
944 ngx_event_t *rev; | |
945 ngx_connection_t *c; | |
946 ngx_mail_core_srv_conf_t *cscf; | |
947 | |
948 c = s->connection; | |
949 rev = c->read; | |
950 | |
951 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
952 | |
953 rev->handler = cscf->protocol->auth_state; | |
954 | |
955 s->auth_method = NGX_MAIL_AUTH_PLAIN; | |
956 | |
957 c->log->action = "in auth state"; | |
958 | |
959 if (s->out.len == 0) { | |
960 s->out = s->auth_err; | |
961 s->quit = s->auth_quit; | |
962 ngx_str_null(&s->auth_err); | |
963 | |
964 s->state = 0; | |
965 s->mail_state = 0; | |
966 s->tag.len = 0; | |
967 | |
968 } else { | |
969 s->auth_err.len -= s->tag.len; | |
970 s->auth_err.data += s->tag.len; | |
971 } | |
972 | |
973 ngx_mail_send(c->write); | |
974 | |
975 if (c->destroyed) { | |
976 return; | |
977 } | |
978 | |
979 ngx_add_timer(rev, cscf->timeout); | |
980 | |
981 if (rev->ready) { | |
982 rev->handler(rev); | |
983 return; | |
984 } | |
985 | |
986 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
987 ngx_mail_close_connection(c); | |
914 } | 988 } |
915 } | 989 } |
916 | 990 |
917 | 991 |
918 static ngx_int_t | 992 static ngx_int_t |