Repository navigation
[#246] Make STARTTLS mandatory: support starttls.required in external.email - #247
Conversation
maximthomas
left a comment
There was a problem hiding this comment.
Review action: Approve — mergeable as is; one cosmetic UI issue and two test pins, all non-blocking. Reviewed the last commit, 2ab4ef0, as the description asks; #206's commits are not reviewed here.
praise: The fix sits where the downgrade is and closes the road JavaMail would otherwise open.
requiredimpliesenableinEmailClient.java:106-110, so the #206 trust settings and host check also apply when onlyrequiredis set, the case JavaMail 1.4.7 would otherwise run STARTTLS without them.startTlsRequiredStopsBeforeMailWhenTheServerDoesNotOfferItandstartTlsWithoutRequiredSendsInClearWhenTheServerDoesNotOfferItdrive a real send againstStartTlsStrippingServer; they also run on the Windows leg (build-maven windows-latest 26: 17/17 in the module).value="true"on the new switch makes form2js save an unchecked switch asfalse, so the #206starttlsmerge cannot keep a staletrue.
issue (non-blocking): A stored required: true without enable: true renders "Use STARTTLS" off.
openidm-ui/openidm-ui-admin/src/main/resources/templates/admin/settings/EmailConfigTemplate.html:58, :69
The template checks config.starttls.enable and config.starttls.required separately, and syncStartTls runs only on change (setup() triggers validate), so nothing reconciles them at render. "starttls": {"required": true} — valid per chap-mail.adoc, which says required implies enable — shows "Use STARTTLS" off and "Require STARTTLS" on, while EmailClient runs STARTTLS. The UI shows a state the server does not apply. Saving untouched keeps required: true, so nothing is downgraded.
<input type="checkbox" name="starttls.enable" id="emailTLS" value="true" {{#if config.starttls.enable}}checked{{else}}{{#if config.starttls.required}}checked{{/if}}{{/if}}/><span></span>suggestion (non-blocking): The save test's hand-written fixture does not pin the template's name="starttls.required" value="true".
openidm-ui/openidm-ui-admin/src/test/qunit/org/forgerock/openidm/ui/admin/settings/EmailConfigViewTest.js:54, openidm-ui/openidm-ui-admin/src/main/resources/templates/admin/settings/EmailConfigTemplate.html:69
save() is unchanged by this commit, so the case exercises #206's merge and is green at the parent a997a14. Dropping value="true" or renaming name on template line 69 leaves it green. In the real form, form2js then skips the unchecked switch, the merge at EmailConfigView.js:152 keeps a stored required: true, and the admin cannot clear it — the stale-true case the description says is prevented. Not run: whether parentRender can fetch the template in the grunt-qunit page.
QUnit.test("the rendered Require STARTTLS switch saves false when unchecked", function (assert) {
var done = assert.async(), saved,
read = sinon.stub(ConfigDelegate, "readEntity", function () {
return $.Deferred().resolve({ host: "smtp.example.com", starttls: { enable: true, required: true } });
}),
update = sinon.stub(ConfigDelegate, "updateEntity", function (id, config) { saved = config; return $.Deferred(); });
$("#qunit-fixture").html('<div id="emailContainer"></div>');
EmailConfigView.render([], function () {
EmailConfigView.$el.find("#emailTLSRequired").prop("checked", false);
EmailConfigView.save({ preventDefault: $.noop });
read.restore(); update.restore();
assert.strictEqual(saved.starttls.required, false, "the template's switch reaches the saved config");
done();
});
});Pin: the case turns red when value="true" is dropped or name="starttls.required" is renamed on template line 69.
suggestion (non-blocking): The new change #emailTLS / change #emailTLSRequired bindings are not tested.
openidm-ui/openidm-ui-admin/src/main/js/org/forgerock/openidm/ui/admin/settings/EmailConfigView.js:40-41
'STARTTLS required implies STARTTLS in the form' calls syncStartTls by hand, and no admin QUnit case delegates a view's events map. Deleting both events entries leaves every case green, and in the real form ticking "Require STARTTLS" would leave "Use STARTTLS" off. Not run.
QUnit.test("the STARTTLS switches stay consistent on change", function (assert) {
$("#qunit-fixture").html('<input type="checkbox" id="emailTLS">' +
'<input type="checkbox" id="emailTLSRequired">');
EmailConfigView.setElement($("#qunit-fixture"));
$("#emailTLSRequired").prop("checked", true).trigger("change");
assert.ok($("#emailTLS").prop("checked"), "checking required turns STARTTLS on");
$("#emailTLS").prop("checked", false).trigger("change");
assert.notOk($("#emailTLSRequired").prop("checked"), "turning STARTTLS off clears required");
EmailConfigView.undelegateEvents();
});Pin: the case turns red when either change entry at EmailConfigView.js:40-41, or the id it selects, is deleted or misspelled.
STARTTLS was opportunistic: when the server's EHLO reply did not offer it, JavaMail went on in clear, so an on-path attacker who stripped STARTTLS got the SMTP credentials and the message. starttls.required maps to mail.smtp.starttls.required and fails the send instead. It defaults to false to keep servers without STARTTLS working, and implies enable, because JavaMail issues STARTTLS for required alone and the trust settings must apply then too. The Admin UI gets a "Require STARTTLS" switch, the samples set it, and chap-mail.adoc documents it. Fixes OpenIdentityPlatform#246
- EmailConfigTemplate: render "Use STARTTLS" on when only starttls.required is stored, since required implies enable in EmailClient - EmailConfigViewTest: render the real template, so the save case pins the Require switch's name and value="true", and drive both switches through change events, so the events map is covered
2ab4ef0 to
def91dd
Compare
|
@maximthomas All three points are addressed in def91dd. #206 is merged, so the branch is rebased onto issue: a stored suggestion: the save case did not pin the template's
suggestion: the Mutation checks against the built
Local runs: |
maximthomas
left a comment
There was a problem hiding this comment.
praise: The change sits where the downgrade happens, and the tests are measured, not asserted.
EmailClient(EmailClient.java:106-114):requiredimpliesenableand maps tomail.smtp.starttls.required, so{enable: false, required: true}still gets the #206 trust settings.EmailConfigTemplate.html:58now renders "Use STARTTLS" on for a storedrequired-only config, which matches whatEmailClientapplies. This closes the round-1 render mismatch.- The mutation claims hold when run. Deleting the
mail.smtp.starttls.requiredput turns 4EmailClientTestcases red, the STARTTLS-stripping server case among them. DroppingstartTLSRequired ||turnsstartTlsRequiredImpliesStartTlsred. Each of the template fallback, the Require switch'svalue="true"and thechange #emailTLSRequiredbinding, when removed, turns exactly oneEmailConfigViewTestcase red (127 run, 1 failed each).
|
Merged the current The PR's own two commits are untouched, and the merge brings no change of its own: its tree is identical to a rebase of the two commits onto |
Fixes #246
Problem
STARTTLS in
external.emailis opportunistic. If the server's EHLO reply does not offer STARTTLS, javax.mail 1.4.7 goes on in clear unlessmail.smtp.starttls.requiredis set. An on-path attacker who strips STARTTLS therefore receives the SMTP credentials and the message, and the certificate checks from #206 never run.Change
EmailClient: new optionalstarttls.required(defaultfalse), mapped tomail.smtp.starttls.required.requiredimpliesenable. javax.mail 1.4.7'sSMTPTransportissues STARTTLS whenuseStartTLS || requireStartTLS(checked in the bytecode). Without the implication,{enable: false, required: true}would run STARTTLS without the trust settings from Harden GitHub workflows and SMTP STARTTLS trust #206, that is, without the host-name check.false, so servers without STARTTLS keep working. Bothsamples/*/external.email.json(smtp.gmail.com:587) and the example inchap-mail.adocset"required" : true.{"required": true}withoutenablerenders "Use STARTTLS" on, matching whatEmailClientapplies.false, because form2js returnsfalsefor an uncheckedvalue="true"checkbox, so thestarttlsmerge from Harden GitHub workflows and SMTP STARTTLS trust #206 cannot keep a staletrue.chap-mail.adocdocumentsrequired, the downgrade it prevents, and that it impliesenable.Tests
EmailClientTest:false,requiredsets the property, andrequiredimpliesenableandcheckserveridentity.required, the send fails with "STARTTLS is required" and the server never seesMAIL FROM.mail.smtp.starttls.requiredput turns 4 cases red, including the server case ("sent over a connection without STARTTLS").pom.xml: test-scopedcom.sun.activation:javax.activation:1.2.0. jaxb-api brings in onlyjavax.activation-api, which has no implementation classes, sosend()in a test failed withNoClassDefFoundError: com/sun/activation/registries/LogSupport.EmailConfigViewTest.js:EmailConfigTemplate.html: a storedrequiredalone shows "Use STARTTLS" on, and unchecking the rendered "Require STARTTLS" switch savesrequired: falseover a storedtrue.changeevents, so the view'seventsmap is covered.requiredfallback on "Use STARTTLS", droppingvalue="true"or renamingname="starttls.required"on the Require switch, and deleting eitherchangebinding each turn one case red.master:openidm-external-email17/17,openidm-ui-commonbuild green, and theopenidm-ui-adminbuild (eslint, QUnit 127/127) green.