Kerberos related audit events
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/a885ef5a Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/a885ef5a Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/a885ef5a Branch: refs/heads/audit_logging Commit: a885ef5a4df3cda4cda413be32a6e81e2ea73275 Parents: 4abfc3e Author: Daniel Gergely <dgerg...@hortonworks.com> Authored: Mon Feb 29 11:30:55 2016 +0100 Committer: Toader, Sebastian <stoa...@hortonworks.com> Committed: Thu Mar 24 13:06:47 2016 +0100 ---------------------------------------------------------------------- .../ambari/server/audit/AbstractAuditEvent.java | 2 +- .../kerberos/AbstractKerberosAuditEvent.java | 76 +++++++ .../ChangeSecurityStateKerberosAuditEvent.java | 99 ++++++++ .../CreateKeyTabKerberosAuditEvent.java | 95 ++++++++ .../CreatePrincipalKerberosAuditEvent.java | 72 ++++++ .../DestroyPrincipalKerberosAuditEvent.java | 73 ++++++ .../event/AddCredentialRequestAuditEvent.java | 105 +++++++++ .../event/AddRequestRequestAuditEvent.java | 84 +++++++ .../eventcreator/CredentialEventCreator.java | 103 +++++++++ .../eventcreator/RequestEventCreator.java | 101 +++++++++ .../eventcreator/UpgradeItemEventCreator.java | 2 +- .../ambari/server/controller/AmbariServer.java | 3 + .../server/controller/ControllerModule.java | 4 + .../serveraction/AbstractServerAction.java | 25 ++ .../kerberos/CreateKeytabFilesServerAction.java | 227 ++++++++++--------- .../kerberos/CreatePrincipalsServerAction.java | 155 +++++++------ .../kerberos/DestroyPrincipalsServerAction.java | 51 +++-- .../kerberos/FinalizeKerberosServerAction.java | 10 + .../kerberos/KerberosServerAction.java | 1 + 19 files changed, 1089 insertions(+), 199 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/AbstractAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/AbstractAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/AbstractAuditEvent.java index 639b78f..d3c7be3 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/audit/AbstractAuditEvent.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/AbstractAuditEvent.java @@ -37,7 +37,7 @@ public abstract class AbstractAuditEvent implements AuditEvent { * @param <T> the type of the concrete audit event built by this builder * @param <TBuilder> the type of the concrete audit event builder. */ - static abstract class AbstractAuditEventBuilder<T extends AbstractAuditEvent, TBuilder extends AbstractAuditEventBuilder<T, TBuilder>> + protected static abstract class AbstractAuditEventBuilder<T extends AbstractAuditEvent, TBuilder extends AbstractAuditEventBuilder<T, TBuilder>> implements AuditEventBuilder<T> { private DateTime timestamp; http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/AbstractKerberosAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/AbstractKerberosAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/AbstractKerberosAuditEvent.java new file mode 100644 index 0000000..899432c --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/AbstractKerberosAuditEvent.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.ambari.server.audit.kerberos; + + +import javax.annotation.concurrent.Immutable; + +import org.apache.ambari.server.audit.AbstractAuditEvent; + +@Immutable +public class AbstractKerberosAuditEvent extends AbstractAuditEvent { + static abstract class AbstractKerberosAuditEventBuilder<T extends AbstractKerberosAuditEvent, TBuilder extends AbstractKerberosAuditEventBuilder<T, TBuilder>> + extends AbstractAuditEvent.AbstractAuditEventBuilder<T, TBuilder> { + + protected String operation; + protected String reasonOfFailure; + + /** + * Builds and audit log message based on the member variables + * @param builder builder for the audit event details. + */ + @Override + protected void buildAuditMessage(StringBuilder builder) { + builder + .append("Operation(") + .append(operation); + + builder.append("), Status(") + .append(reasonOfFailure == null ? "Success" : "Failed"); + + if(reasonOfFailure != null) { + builder.append("), Reason of failure(") + .append(reasonOfFailure); + } + + builder.append(")"); + } + + public TBuilder withOperation(String operation) { + this.operation = operation; + return (TBuilder) this; + } + + public TBuilder withReasonOfFailure(String reasonOfFailure) { + this.reasonOfFailure = reasonOfFailure; + return (TBuilder) this; + } + } + + protected AbstractKerberosAuditEvent() { + } + + /** + * {@inheritDoc} + */ + protected AbstractKerberosAuditEvent(AbstractKerberosAuditEventBuilder<?, ?> builder) { + super(builder); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/ChangeSecurityStateKerberosAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/ChangeSecurityStateKerberosAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/ChangeSecurityStateKerberosAuditEvent.java new file mode 100644 index 0000000..899addc --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/ChangeSecurityStateKerberosAuditEvent.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.ambari.server.audit.kerberos; + +import javax.annotation.concurrent.Immutable; + +@Immutable +public class ChangeSecurityStateKerberosAuditEvent extends AbstractKerberosAuditEvent { + + public static class ChangeSecurityStateKerberosAuditEventBuilder extends AbstractKerberosAuditEventBuilder<ChangeSecurityStateKerberosAuditEvent, ChangeSecurityStateKerberosAuditEventBuilder> { + + private String service; + private String component; + private String hostName; + private String state; + + private ChangeSecurityStateKerberosAuditEventBuilder() { + this.withOperation("Security state change"); + } + + @Override + protected void buildAuditMessage(StringBuilder builder) { + super.buildAuditMessage(builder); + + builder + .append(", Hostname(") + .append(hostName) + .append("), Service(") + .append(service) + .append("), Component(") + .append(component) + .append("), State(") + .append(state) + .append(")"); + } + + /** + * {@inheritDoc} + */ + @Override + protected ChangeSecurityStateKerberosAuditEvent newAuditEvent() { + return new ChangeSecurityStateKerberosAuditEvent(this); + } + + public ChangeSecurityStateKerberosAuditEventBuilder withService(String service) { + this.service = service; + return this; + } + + public ChangeSecurityStateKerberosAuditEventBuilder withComponent(String component) { + this.component = component; + return this; + } + + public ChangeSecurityStateKerberosAuditEventBuilder withHostName(String hostName) { + this.hostName = hostName; + return this; + } + + public ChangeSecurityStateKerberosAuditEventBuilder withState(String state) { + this.state = state; + return this; + } + } + + private ChangeSecurityStateKerberosAuditEvent() { + } + + /** + * {@inheritDoc} + */ + private ChangeSecurityStateKerberosAuditEvent(ChangeSecurityStateKerberosAuditEventBuilder builder) { + super(builder); + } + + /** + * Returns an builder for {@link ChangeSecurityStateKerberosAuditEvent} + * @return a builder instance + */ + public static ChangeSecurityStateKerberosAuditEventBuilder builder() { + return new ChangeSecurityStateKerberosAuditEventBuilder(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/CreateKeyTabKerberosAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/CreateKeyTabKerberosAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/CreateKeyTabKerberosAuditEvent.java new file mode 100644 index 0000000..1c2d52b --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/CreateKeyTabKerberosAuditEvent.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.ambari.server.audit.kerberos; + +import javax.annotation.concurrent.Immutable; + +@Immutable +public class CreateKeyTabKerberosAuditEvent extends AbstractKerberosAuditEvent { + + public static class CreateKeyTabKerberosAuditEventBuilder extends AbstractKerberosAuditEventBuilder<CreateKeyTabKerberosAuditEvent, CreateKeyTabKerberosAuditEventBuilder> { + + private String keyTabFilePath; + private String hostName; + private String principal; + + private CreateKeyTabKerberosAuditEventBuilder() { + this.withOperation("Keytab file creation"); + } + + @Override + protected void buildAuditMessage(StringBuilder builder) { + super.buildAuditMessage(builder); + + builder + .append(", Principal(") + .append(principal) + .append("), Hostname(") + .append(hostName) + .append("), Keytab file(") + .append(keyTabFilePath) + .append(")"); + } + + /** + * {@inheritDoc} + */ + @Override + protected CreateKeyTabKerberosAuditEvent newAuditEvent() { + return new CreateKeyTabKerberosAuditEvent(this); + } + + public CreateKeyTabKerberosAuditEventBuilder withKeyTabFilePath(String keyTabFilePath) { + this.keyTabFilePath = keyTabFilePath; + return this; + } + + public CreateKeyTabKerberosAuditEventBuilder withHostName(String hostName) { + this.hostName = hostName; + return this; + } + + public CreateKeyTabKerberosAuditEventBuilder withPrincipal(String principal) { + this.principal = principal; + return this; + } + + public boolean hasPrincipal() { + return principal != null; + } + } + + private CreateKeyTabKerberosAuditEvent() { + } + + /** + * {@inheritDoc} + */ + private CreateKeyTabKerberosAuditEvent(CreateKeyTabKerberosAuditEventBuilder builder) { + super(builder); + } + + /** + * Returns an builder for {@link CreateKeyTabKerberosAuditEvent} + * @return a builder instance + */ + public static CreateKeyTabKerberosAuditEventBuilder builder() { + return new CreateKeyTabKerberosAuditEventBuilder(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/CreatePrincipalKerberosAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/CreatePrincipalKerberosAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/CreatePrincipalKerberosAuditEvent.java new file mode 100644 index 0000000..82790ab --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/CreatePrincipalKerberosAuditEvent.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.ambari.server.audit.kerberos; + +import javax.annotation.concurrent.Immutable; + +@Immutable +public class CreatePrincipalKerberosAuditEvent extends AbstractKerberosAuditEvent { + + public static class CreatePrincipalKerberosAuditEventBuilder extends AbstractKerberosAuditEventBuilder<CreatePrincipalKerberosAuditEvent, CreatePrincipalKerberosAuditEventBuilder> { + + private String principal; + + private CreatePrincipalKerberosAuditEventBuilder() { + this.withOperation("Principal creation"); + } + + @Override + protected void buildAuditMessage(StringBuilder builder) { + super.buildAuditMessage(builder); + builder.append("), Principal(") + .append(principal); + } + + /** + * {@inheritDoc} + */ + @Override + protected CreatePrincipalKerberosAuditEvent newAuditEvent() { + return new CreatePrincipalKerberosAuditEvent(this); + } + + public CreatePrincipalKerberosAuditEventBuilder withPrincipal(String principal) { + this.principal = principal; + return this; + } + } + + private CreatePrincipalKerberosAuditEvent() { + } + + /** + * {@inheritDoc} + */ + private CreatePrincipalKerberosAuditEvent(CreatePrincipalKerberosAuditEventBuilder builder) { + super(builder); + } + + /** + * Returns an builder for {@link CreatePrincipalKerberosAuditEvent} + * @return a builder instance + */ + public static CreatePrincipalKerberosAuditEventBuilder builder() { + return new CreatePrincipalKerberosAuditEventBuilder(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/DestroyPrincipalKerberosAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/DestroyPrincipalKerberosAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/DestroyPrincipalKerberosAuditEvent.java new file mode 100644 index 0000000..911f82c --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/kerberos/DestroyPrincipalKerberosAuditEvent.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.ambari.server.audit.kerberos; + +import javax.annotation.concurrent.Immutable; + +@Immutable +public class DestroyPrincipalKerberosAuditEvent extends AbstractKerberosAuditEvent { + + public static class DestroyPrincipalKerberosAuditEventBuilder extends AbstractKerberosAuditEventBuilder<DestroyPrincipalKerberosAuditEvent, DestroyPrincipalKerberosAuditEventBuilder> { + + private String principal; + + private DestroyPrincipalKerberosAuditEventBuilder() { + this.withOperation("Principal removal"); + } + + @Override + protected void buildAuditMessage(StringBuilder builder) { + super.buildAuditMessage(builder); + + builder.append("), Principal(") + .append(principal); + } + + /** + * {@inheritDoc} + */ + @Override + protected DestroyPrincipalKerberosAuditEvent newAuditEvent() { + return new DestroyPrincipalKerberosAuditEvent(this); + } + + public DestroyPrincipalKerberosAuditEventBuilder withPrincipal(String principal) { + this.principal = principal; + return this; + } + } + + private DestroyPrincipalKerberosAuditEvent() { + } + + /** + * {@inheritDoc} + */ + private DestroyPrincipalKerberosAuditEvent(DestroyPrincipalKerberosAuditEventBuilder builder) { + super(builder); + } + + /** + * Returns an builder for {@link DestroyPrincipalKerberosAuditEvent} + * @return a builder instance + */ + public static DestroyPrincipalKerberosAuditEventBuilder builder() { + return new DestroyPrincipalKerberosAuditEventBuilder(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/event/AddCredentialRequestAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/event/AddCredentialRequestAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/event/AddCredentialRequestAuditEvent.java new file mode 100644 index 0000000..780e2eb --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/event/AddCredentialRequestAuditEvent.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.ambari.server.audit.request.event; + +import java.util.List; +import java.util.Map; + +import org.apache.ambari.server.audit.request.RequestAuditEvent; + +public class AddCredentialRequestAuditEvent extends RequestAuditEvent { + + public static class AddCredentialAuditEventBuilder extends RequestAuditEventBuilder<AddCredentialRequestAuditEvent, AddCredentialAuditEventBuilder> { + + private String type; + + private String clusterName; + + private String principal; + + private String alias; + + public AddCredentialAuditEventBuilder() { + super.withOperation("Credential addition"); + } + + @Override + protected AddCredentialRequestAuditEvent newAuditEvent() { + return new AddCredentialRequestAuditEvent(this); + } + + /** + * Appends to the event the details of the incoming request. + * @param builder builder for the audit event details. + */ + @Override + protected void buildAuditMessage(StringBuilder builder) { + super.buildAuditMessage(builder); + + builder.append(", Type(") + .append(type) + .append("), Principal(") + .append(principal) + .append("), Alias(") + .append(alias) + .append("), Cluster name(") + .append(clusterName) + .append(")"); + } + + public AddCredentialAuditEventBuilder withType(String type) { + this.type = type; + return this; + } + + public AddCredentialAuditEventBuilder withClusterName(String clusterName) { + this.clusterName = clusterName; + return this; + } + + public AddCredentialAuditEventBuilder withPrincipal(String principal) { + this.principal = principal; + return this; + } + + public AddCredentialAuditEventBuilder withAlias(String alias) { + this.alias = alias; + return this; + } + } + + protected AddCredentialRequestAuditEvent() { + } + + /** + * {@inheritDoc} + */ + protected AddCredentialRequestAuditEvent(AddCredentialAuditEventBuilder builder) { + super(builder); + } + + /** + * Returns an builder for {@link AddCredentialRequestAuditEvent} + * @return a builder instance + */ + public static AddCredentialAuditEventBuilder builder() { + return new AddCredentialAuditEventBuilder(); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/event/AddRequestRequestAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/event/AddRequestRequestAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/event/AddRequestRequestAuditEvent.java new file mode 100644 index 0000000..2332269 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/event/AddRequestRequestAuditEvent.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.ambari.server.audit.request.event; + +import org.apache.ambari.server.audit.request.RequestAuditEvent; + +public class AddRequestRequestAuditEvent extends RequestAuditEvent { + + public static class AddRequestAuditEventBuilder extends RequestAuditEventBuilder<AddRequestRequestAuditEvent, AddRequestAuditEventBuilder> { + + private String command; + + private String clusterName; + + public AddRequestAuditEventBuilder() { + super.withOperation("Request from server"); + } + + @Override + protected AddRequestRequestAuditEvent newAuditEvent() { + return new AddRequestRequestAuditEvent(this); + } + + /** + * Appends to the event the details of the incoming request. + * @param builder builder for the audit event details. + */ + @Override + protected void buildAuditMessage(StringBuilder builder) { + super.buildAuditMessage(builder); + + builder.append("), Command(") + .append(command) + .append("), Cluster name(") + .append(clusterName) + .append(")"); + } + + public AddRequestAuditEventBuilder withClusterName(String clusterName) { + this.clusterName = clusterName; + return this; + } + + public AddRequestAuditEventBuilder withCommand(String command) { + this.command = command; + return this; + } + } + + protected AddRequestRequestAuditEvent() { + } + + /** + * {@inheritDoc} + */ + protected AddRequestRequestAuditEvent(AddRequestAuditEventBuilder builder) { + super(builder); + } + + /** + * Returns an builder for {@link AddRequestRequestAuditEvent} + * @return a builder instance + */ + public static AddRequestAuditEventBuilder builder() { + return new AddRequestAuditEventBuilder(); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/CredentialEventCreator.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/CredentialEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/CredentialEventCreator.java new file mode 100644 index 0000000..ed7c95d --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/CredentialEventCreator.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.ambari.server.audit.request.eventcreator; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.apache.ambari.server.api.services.Request; +import org.apache.ambari.server.api.services.Result; +import org.apache.ambari.server.api.services.ResultStatus; +import org.apache.ambari.server.audit.AuditEvent; +import org.apache.ambari.server.audit.request.RequestAuditEventCreator; +import org.apache.ambari.server.audit.request.event.AddCredentialRequestAuditEvent; +import org.apache.ambari.server.audit.request.event.UpdateUpgradeItemRequestAuditEvent; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.controller.utilities.PropertyHelper; +import org.joda.time.DateTime; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; + +/** + * This creator handles crednetial requests + * For resource type {@link Resource.Type#Upgrade} + * and request types {@link Request.Type#POST} + */ +public class CredentialEventCreator implements RequestAuditEventCreator { + + /** + * Set of {@link Request.Type}s that are handled by this plugin + */ + private Set<Request.Type> requestTypes = new HashSet<Request.Type>(); + + { + requestTypes.add(Request.Type.POST); + } + + /** + * {@inheritDoc} + */ + @Override + public Set<Request.Type> getRequestTypes() { + return requestTypes; + } + + /** + * {@inheritDoc} + */ + @Override + public Set<Resource.Type> getResourceTypes() { + return Collections.singleton(Resource.Type.Credential); + } + + /** + * {@inheritDoc} + */ + @Override + public Set<ResultStatus.STATUS> getResultStatuses() { + return null; + } + + @Override + public AuditEvent createAuditEvent(Request request, Result result) { + String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername(); + + return AddCredentialRequestAuditEvent.builder() + .withTimestamp(DateTime.now()) + .withRequestType(request.getRequestType()) + .withResultStatus(result.getStatus()) + .withUrl(request.getURI()) + .withRemoteIp(request.getRemoteAddress()) + .withUserName(username) + .withClusterName(getProperty(request, "cluster_name")) + .withType(getProperty(request, "type")) + .withAlias(getProperty(request, "alias")) + .withPrincipal(getProperty(request, "principal")) + .build(); + + } + + private String getProperty(Request request, String propertyName) { + if(!request.getBody().getPropertySets().isEmpty()) { + return String.valueOf(request.getBody().getPropertySets().iterator().next().get(PropertyHelper.getPropertyId("Credential",propertyName))); + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/RequestEventCreator.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/RequestEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/RequestEventCreator.java new file mode 100644 index 0000000..d96edf2 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/RequestEventCreator.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.ambari.server.audit.request.eventcreator; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.ambari.server.api.services.Request; +import org.apache.ambari.server.api.services.Result; +import org.apache.ambari.server.api.services.ResultStatus; +import org.apache.ambari.server.audit.AuditEvent; +import org.apache.ambari.server.audit.StartOperationFailedAuditEvent; +import org.apache.ambari.server.audit.StartOperationSucceededAuditEvent; +import org.apache.ambari.server.audit.request.RequestAuditEventCreator; +import org.apache.ambari.server.audit.request.event.AddRequestRequestAuditEvent; +import org.apache.ambari.server.audit.request.event.DeleteServiceRequestAuditEvent; +import org.apache.ambari.server.controller.internal.RequestOperationLevel; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.controller.utilities.PropertyHelper; +import org.joda.time.DateTime; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; + +/** + * This creator handles request type requests + * For resource type {@link Resource.Type#Request} + * and request types {@link Request.Type#POST} + */ +public class RequestEventCreator implements RequestAuditEventCreator { + + /** + * Set of {@link Request.Type}s that are handled by this plugin + */ + private Set<Request.Type> requestTypes = new HashSet<Request.Type>(); + + { + requestTypes.add(Request.Type.POST); + } + + private Set<Resource.Type> resourceTypes = new HashSet<Resource.Type>(); + { + resourceTypes.add(Resource.Type.Request); + } + + /** {@inheritDoc} */ + @Override + public Set<Request.Type> getRequestTypes() { + return requestTypes; + } + + /** {@inheritDoc} */ + @Override + public Set<Resource.Type> getResourceTypes() { + return resourceTypes; + } + + /** {@inheritDoc} */ + @Override + public Set<ResultStatus.STATUS> getResultStatuses() { + // null makes this default + return null; + } + + @Override + public AuditEvent createAuditEvent(Request request, Result result) { + String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername(); + + switch(request.getRequestType()) { + case POST: + return AddRequestRequestAuditEvent.builder() + .withTimestamp(DateTime.now()) + .withRequestType(request.getRequestType()) + .withResultStatus(result.getStatus()) + .withUrl(request.getURI()) + .withRemoteIp(request.getRemoteAddress()) + .withUserName(username) + .withCommand(request.getBody().getRequestInfoProperties().get("command")) + .withClusterName(request.getBody().getRequestInfoProperties().get(RequestOperationLevel.OPERATION_CLUSTER_ID)) + .build(); + default: + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/UpgradeItemEventCreator.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/UpgradeItemEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/UpgradeItemEventCreator.java index dff546c..6118dad 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/UpgradeItemEventCreator.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/UpgradeItemEventCreator.java @@ -38,7 +38,7 @@ import org.springframework.security.core.userdetails.User; /** * This creator handles upgrade requests * For resource type {@link Resource.Type#Upgrade} - * and request types {@link Request.Type#POST} + * and request types {@link Request.Type#PUT} */ public class UpgradeItemEventCreator implements RequestAuditEventCreator { http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java index a5dcdf2..9436e5d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java @@ -104,6 +104,7 @@ import org.apache.ambari.server.security.ldap.AmbariLdapDataPopulator; import org.apache.ambari.server.security.unsecured.rest.CertificateDownload; import org.apache.ambari.server.security.unsecured.rest.CertificateSign; import org.apache.ambari.server.security.unsecured.rest.ConnectionInfo; +import org.apache.ambari.server.serveraction.AbstractServerAction; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.topology.AmbariContext; import org.apache.ambari.server.topology.BlueprintFactory; @@ -884,6 +885,8 @@ public class AmbariServer { LogoutService.init(injector.getInstance(AuditLogger.class)); RetryHelper.init(configs.getOperationsRetryAttempts()); + + AbstractServerAction.init(injector); } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java index f489f54..74cd698 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java @@ -48,6 +48,7 @@ import org.apache.ambari.server.audit.request.eventcreator.AlertGroupEventCreato import org.apache.ambari.server.audit.request.eventcreator.AlertTargetEventCreator; import org.apache.ambari.server.audit.request.eventcreator.BlueprintEventCreator; import org.apache.ambari.server.audit.request.eventcreator.BlueprintExportEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.CredentialEventCreator; import org.apache.ambari.server.audit.request.eventcreator.HostEventCreator; import org.apache.ambari.server.audit.request.eventcreator.PrivilegeEventCreator; import org.apache.ambari.server.audit.request.eventcreator.GroupEventCreator; @@ -55,6 +56,7 @@ import org.apache.ambari.server.audit.request.eventcreator.MemberEventCreator; import org.apache.ambari.server.audit.request.eventcreator.RecommendationIgnoreEventCreator; import org.apache.ambari.server.audit.request.eventcreator.RepositoryEventCreator; import org.apache.ambari.server.audit.request.eventcreator.RepositoryVersionEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.RequestEventCreator; import org.apache.ambari.server.audit.request.eventcreator.ServiceConfigDownloadEventCreator; import org.apache.ambari.server.audit.request.eventcreator.UnauthorizedEventCreator; import org.apache.ambari.server.audit.request.eventcreator.ConfigurationChangeEventCreator; @@ -434,6 +436,8 @@ public class ControllerModule extends AbstractModule { auditLogEventCreatorBinder.addBinding().to(UpgradeItemEventCreator.class); auditLogEventCreatorBinder.addBinding().to(RecommendationIgnoreEventCreator.class); auditLogEventCreatorBinder.addBinding().to(ValidationIgnoreEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(CredentialEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(RequestEventCreator.class); bind(RequestAuditLogger.class).to(RequestAuditLoggerImpl.class); } http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/AbstractServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/AbstractServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/AbstractServerAction.java index 33191bf..0fd530a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/AbstractServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/AbstractServerAction.java @@ -24,11 +24,16 @@ import org.apache.ambari.server.actionmanager.HostRoleCommand; import org.apache.ambari.server.actionmanager.HostRoleStatus; import org.apache.ambari.server.agent.CommandReport; import org.apache.ambari.server.agent.ExecutionCommand; +import org.apache.ambari.server.audit.AuditEvent; +import org.apache.ambari.server.audit.AuditLogger; +import org.apache.ambari.server.controller.AmbariServer; import org.apache.ambari.server.utils.StageUtils; import java.util.Collections; import java.util.Map; +import com.google.inject.Injector; + /** * AbstractServerActionImpl is an abstract implementation of a ServerAction. * <p/> @@ -52,6 +57,22 @@ public abstract class AbstractServerAction implements ServerAction { */ protected ActionLog actionLog = new ActionLog(); + /** + * Guice injector + */ + private static Injector injector; + + /** + * Statically initialize the Injector + * <p/> + * This should only be used for unit tests. + * + * @param injector the Injector to (manually) statically inject + */ + public static void init(Injector injector) { + AbstractServerAction.injector = injector; + } + @Override public ExecutionCommand getExecutionCommand() { return this.executionCommand; @@ -175,4 +196,8 @@ public abstract class AbstractServerAction implements ServerAction { return getConfigurations().get(configurationName); } + protected void auditLog(AuditEvent ae) { + injector.getInstance(AuditLogger.class).log(ae); + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java index 8aa816d..1af0245 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java @@ -22,6 +22,8 @@ import com.google.inject.Inject; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.actionmanager.HostRoleStatus; import org.apache.ambari.server.agent.CommandReport; +import org.apache.ambari.server.audit.kerberos.AbstractKerberosAuditEvent; +import org.apache.ambari.server.audit.kerberos.CreateKeyTabKerberosAuditEvent; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.orm.dao.HostDAO; import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO; @@ -31,6 +33,7 @@ import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity; import org.apache.ambari.server.serveraction.ActionLog; import org.apache.commons.codec.digest.DigestUtils; import org.apache.directory.server.kerberos.shared.keytab.Keytab; +import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -147,138 +150,150 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) throws AmbariException { - CommandReport commandReport = null; - if (identityRecord != null) { - String message; - String dataDirectory = getDataDirectoryPath(); - - if (operationHandler == null) { - message = String.format("Failed to create keytab file for %s, missing KerberosOperationHandler", evaluatedPrincipal); - actionLog.writeStdErr(message); - LOG.error(message); - commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); - } else if (dataDirectory == null) { - message = "The data directory has not been set. Generated keytab files can not be stored."; - LOG.error(message); - commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); - } else { - Map<String, String> principalPasswordMap = getPrincipalPasswordMap(requestSharedDataContext); - Map<String, Integer> principalKeyNumberMap = getPrincipalKeyNumberMap(requestSharedDataContext); - - String hostName = identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME); - String keytabFilePath = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH); - - if ((hostName != null) && !hostName.isEmpty() && (keytabFilePath != null) && !keytabFilePath.isEmpty()) { - Set<String> visitedPrincipalKeys = visitedIdentities.get(evaluatedPrincipal); - String visitationKey = String.format("%s|%s", hostName, keytabFilePath); - - if ((visitedPrincipalKeys == null) || !visitedPrincipalKeys.contains(visitationKey)) { - // Look up the current evaluatedPrincipal's password. - // If found create the keytab file, else try to find it in the cache. - String password = principalPasswordMap.get(evaluatedPrincipal); - Integer keyNumber = principalKeyNumberMap.get(evaluatedPrincipal); - - message = String.format("Creating keytab file for %s on host %s", evaluatedPrincipal, hostName); - LOG.info(message); - actionLog.writeStdOut(message); - - // Determine where to store the keytab file. It should go into a host-specific - // directory under the previously determined data directory. - File hostDirectory = new File(dataDirectory, hostName); - - // Ensure the host directory exists... - if (!hostDirectory.exists() && hostDirectory.mkdirs()) { - // Make sure only Ambari has access to this directory. - ensureAmbariOnlyAccess(hostDirectory); - } - if (hostDirectory.exists()) { - File destinationKeytabFile = new File(hostDirectory, DigestUtils.sha1Hex(keytabFilePath)); - HostEntity hostEntity = hostDAO.findByName(hostName); - if (hostEntity == null) { - message = "Failed to find HostEntity for hostname = " + hostName; - actionLog.writeStdErr(message); - LOG.error(message); - commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); - return commandReport; + CreateKeyTabKerberosAuditEvent.CreateKeyTabKerberosAuditEventBuilder auditEventBuilder = CreateKeyTabKerberosAuditEvent.builder().withTimestamp(DateTime.now()); + CommandReport commandReport = null; + String message = null; + try { + if (identityRecord != null) { + String dataDirectory = getDataDirectoryPath(); + + if (operationHandler == null) { + message = String.format("Failed to create keytab file for %s, missing KerberosOperationHandler", evaluatedPrincipal); + actionLog.writeStdErr(message); + LOG.error(message); + commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); + } else if (dataDirectory == null) { + message = "The data directory has not been set. Generated keytab files can not be stored."; + LOG.error(message); + commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); + } else { + Map<String, String> principalPasswordMap = getPrincipalPasswordMap(requestSharedDataContext); + Map<String, Integer> principalKeyNumberMap = getPrincipalKeyNumberMap(requestSharedDataContext); + + String hostName = identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME); + String keytabFilePath = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH); + + if ((hostName != null) && !hostName.isEmpty() && (keytabFilePath != null) && !keytabFilePath.isEmpty()) { + Set<String> visitedPrincipalKeys = visitedIdentities.get(evaluatedPrincipal); + String visitationKey = String.format("%s|%s", hostName, keytabFilePath); + + if ((visitedPrincipalKeys == null) || !visitedPrincipalKeys.contains(visitationKey)) { + // Look up the current evaluatedPrincipal's password. + // If found create the keytab file, else try to find it in the cache. + String password = principalPasswordMap.get(evaluatedPrincipal); + Integer keyNumber = principalKeyNumberMap.get(evaluatedPrincipal); + + message = String.format("Creating keytab file for %s on host %s", evaluatedPrincipal, hostName); + LOG.info(message); + actionLog.writeStdOut(message); + auditEventBuilder.withPrincipal(evaluatedPrincipal).withHostName(hostName).withKeyTabFilePath(keytabFilePath); + + // Determine where to store the keytab file. It should go into a host-specific + // directory under the previously determined data directory. + File hostDirectory = new File(dataDirectory, hostName); + + // Ensure the host directory exists... + if (!hostDirectory.exists() && hostDirectory.mkdirs()) { + // Make sure only Ambari has access to this directory. + ensureAmbariOnlyAccess(hostDirectory); } - if (password == null) { - if (kerberosPrincipalHostDAO.exists(evaluatedPrincipal, hostEntity.getHostId())) { - // There is nothing to do for this since it must already exist and we don't want to - // regenerate the keytab - message = String.format("Skipping keytab file for %s, missing password indicates nothing to do", evaluatedPrincipal); - LOG.debug(message); - } else { - KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal); - String cachedKeytabPath = (principalEntity == null) ? null : principalEntity.getCachedKeytabPath(); + if (hostDirectory.exists()) { + File destinationKeytabFile = new File(hostDirectory, DigestUtils.sha1Hex(keytabFilePath)); + HostEntity hostEntity = hostDAO.findByName(hostName); + if (hostEntity == null) { + message = "Failed to find HostEntity for hostname = " + hostName; + actionLog.writeStdErr(message); + LOG.error(message); + commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); + return commandReport; + } - if (cachedKeytabPath == null) { - message = String.format("Failed to create keytab for %s, missing cached file", evaluatedPrincipal); - actionLog.writeStdErr(message); - LOG.error(message); - commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); + if (password == null) { + if (kerberosPrincipalHostDAO.exists(evaluatedPrincipal, hostEntity.getHostId())) { + // There is nothing to do for this since it must already exist and we don't want to + // regenerate the keytab + message = String.format("Skipping keytab file for %s, missing password indicates nothing to do", evaluatedPrincipal); + LOG.debug(message); } else { - try { - operationHandler.createKeytabFile(new File(cachedKeytabPath), destinationKeytabFile); - } catch (KerberosOperationException e) { - message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage()); + KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal); + String cachedKeytabPath = (principalEntity == null) ? null : principalEntity.getCachedKeytabPath(); + + if (cachedKeytabPath == null) { + message = String.format("Failed to create keytab for %s, missing cached file", evaluatedPrincipal); actionLog.writeStdErr(message); - LOG.error(message, e); + LOG.error(message); commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); + } else { + try { + operationHandler.createKeytabFile(new File(cachedKeytabPath), destinationKeytabFile); + } catch (KerberosOperationException e) { + message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage()); + actionLog.writeStdErr(message); + LOG.error(message, e); + commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); + } } } - } - } else { - boolean canCache = ("true".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_IS_CACHABLE))); - - Keytab keytab = createKeytab(evaluatedPrincipal, password, keyNumber, operationHandler, visitedPrincipalKeys != null, canCache, actionLog); + } else { + boolean canCache = ("true".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_IS_CACHABLE))); - if (keytab != null) { - try { - if (operationHandler.createKeytabFile(keytab, destinationKeytabFile)) { - ensureAmbariOnlyAccess(destinationKeytabFile); + Keytab keytab = createKeytab(evaluatedPrincipal, password, keyNumber, operationHandler, visitedPrincipalKeys != null, canCache, actionLog); - message = String.format("Successfully created keytab file for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath()); - LOG.debug(message); - } else { - message = String.format("Failed to create keytab file for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath()); + if (keytab != null) { + try { + if (operationHandler.createKeytabFile(keytab, destinationKeytabFile)) { + ensureAmbariOnlyAccess(destinationKeytabFile); + + message = String.format("Successfully created keytab file for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath()); + LOG.debug(message); + auditEventBuilder.withPrincipal(evaluatedPrincipal).withHostName(hostName).withKeyTabFilePath(destinationKeytabFile.getAbsolutePath()); + } else { + message = String.format("Failed to create keytab file for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath()); + actionLog.writeStdErr(message); + LOG.error(message); + commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); + } + } catch (KerberosOperationException e) { + message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage()); actionLog.writeStdErr(message); - LOG.error(message); + LOG.error(message, e); commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); } - } catch (KerberosOperationException e) { - message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage()); - actionLog.writeStdErr(message); - LOG.error(message, e); + } else { commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); } - } else { - commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); - } - if (visitedPrincipalKeys == null) { - visitedPrincipalKeys = new HashSet<String>(); - visitedIdentities.put(evaluatedPrincipal, visitedPrincipalKeys); - } + if (visitedPrincipalKeys == null) { + visitedPrincipalKeys = new HashSet<String>(); + visitedIdentities.put(evaluatedPrincipal, visitedPrincipalKeys); + } - visitedPrincipalKeys.add(visitationKey); + visitedPrincipalKeys.add(visitationKey); + } + } else { + message = String.format("Failed to create keytab file for %s, the container directory does not exist: %s", + evaluatedPrincipal, hostDirectory.getAbsolutePath()); + actionLog.writeStdErr(message); + LOG.error(message); + commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); } } else { - message = String.format("Failed to create keytab file for %s, the container directory does not exist: %s", - evaluatedPrincipal, hostDirectory.getAbsolutePath()); - actionLog.writeStdErr(message); - LOG.error(message); - commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); + LOG.debug(String.format("Skipping previously processed keytab for %s on host %s", evaluatedPrincipal, hostName)); } - } else { - LOG.debug(String.format("Skipping previously processed keytab for %s on host %s", evaluatedPrincipal, hostName)); } } } + } finally { + if(commandReport != null && HostRoleStatus.FAILED.toString().equals(commandReport.getStatus())) { + auditEventBuilder.withReasonOfFailure(message == null ? "Unknown error" : message); + } + if(commandReport != null || auditEventBuilder.hasPrincipal()) { + auditLog(auditEventBuilder.build()); + } } - return commandReport; } http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java index 8009ae1..09df299 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java @@ -22,12 +22,14 @@ import com.google.inject.Inject; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.actionmanager.HostRoleStatus; import org.apache.ambari.server.agent.CommandReport; +import org.apache.ambari.server.audit.kerberos.CreatePrincipalKerberosAuditEvent; import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO; import org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO; import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity; import org.apache.ambari.server.security.SecurePasswordHelper; import org.apache.ambari.server.serveraction.ActionLog; import org.apache.commons.lang.StringUtils; +import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -173,92 +175,103 @@ public class CreatePrincipalsServerAction extends KerberosServerAction { Map<String, String> kerberosConfiguration, KerberosOperationHandler kerberosOperationHandler, ActionLog actionLog) { + CreatePrincipalKerberosAuditEvent.CreatePrincipalKerberosAuditEventBuilder auditEventBuilder = CreatePrincipalKerberosAuditEvent.builder() + .withTimestamp(DateTime.now()) + .withPrincipal(principal); CreatePrincipalResult result = null; + String message = null; + try { - String message = String.format("Creating principal, %s", principal); - LOG.info(message); - if (actionLog != null) { - actionLog.writeStdOut(message); - } - - Integer length; - Integer minLowercaseLetters; - Integer minUppercaseLetters; - Integer minDigits; - Integer minPunctuation; - Integer minWhitespace; - - if (kerberosConfiguration == null) { - length = null; - minLowercaseLetters = null; - minUppercaseLetters = null; - minDigits = null; - minPunctuation = null; - minWhitespace = null; - } else { - length = toInt(kerberosConfiguration.get("password_length")); - minLowercaseLetters = toInt(kerberosConfiguration.get("password_min_lowercase_letters")); - minUppercaseLetters = toInt(kerberosConfiguration.get("password_min_uppercase_letters")); - minDigits = toInt(kerberosConfiguration.get("password_min_digits")); - minPunctuation = toInt(kerberosConfiguration.get("password_min_punctuation")); - minWhitespace = toInt(kerberosConfiguration.get("password_min_whitespace")); - } - - String password = securePasswordHelper.createSecurePassword(length, minLowercaseLetters, minUppercaseLetters, minDigits, minPunctuation, minWhitespace); + message = String.format("Creating principal, %s", principal); + LOG.info(message); + if (actionLog != null) { + actionLog.writeStdOut(message); + } - try { + Integer length; + Integer minLowercaseLetters; + Integer minUppercaseLetters; + Integer minDigits; + Integer minPunctuation; + Integer minWhitespace; + + if (kerberosConfiguration == null) { + length = null; + minLowercaseLetters = null; + minUppercaseLetters = null; + minDigits = null; + minPunctuation = null; + minWhitespace = null; + } else { + length = toInt(kerberosConfiguration.get("password_length")); + minLowercaseLetters = toInt(kerberosConfiguration.get("password_min_lowercase_letters")); + minUppercaseLetters = toInt(kerberosConfiguration.get("password_min_uppercase_letters")); + minDigits = toInt(kerberosConfiguration.get("password_min_digits")); + minPunctuation = toInt(kerberosConfiguration.get("password_min_punctuation")); + minWhitespace = toInt(kerberosConfiguration.get("password_min_whitespace")); + } - if (kerberosOperationHandler.principalExists(principal)) { - // Create a new password since we need to know what it is. - // A new password/key would have been generated after exporting the keytab anyways. - message = String.format("Principal, %s, already exists, setting new password", principal); - LOG.warn(message); - if (actionLog != null) { - actionLog.writeStdOut(message); - } + String password = securePasswordHelper.createSecurePassword(length, minLowercaseLetters, minUppercaseLetters, minDigits, minPunctuation, minWhitespace); - Integer keyNumber = kerberosOperationHandler.setPrincipalPassword(principal, password); + try { - if (keyNumber != null) { - result = new CreatePrincipalResult(principal, password, keyNumber); - message = String.format("Successfully set password for %s", principal); - LOG.debug(message); - } else { - message = String.format("Failed to set password for %s - unknown reason", principal); - LOG.error(message); + if (kerberosOperationHandler.principalExists(principal)) { + // Create a new password since we need to know what it is. + // A new password/key would have been generated after exporting the keytab anyways. + message = String.format("Principal, %s, already exists, setting new password", principal); + LOG.warn(message); if (actionLog != null) { - actionLog.writeStdErr(message); + actionLog.writeStdOut(message); } - } - } else { - message = String.format("Creating new principal, %s", principal); - LOG.debug(message); - Integer keyNumber = kerberosOperationHandler.createPrincipal(principal, password, isServicePrincipal); - - if (keyNumber != null) { - result = new CreatePrincipalResult(principal, password, keyNumber); - message = String.format("Successfully created new principal, %s", principal); - LOG.debug(message); + Integer keyNumber = kerberosOperationHandler.setPrincipalPassword(principal, password); + + if (keyNumber != null) { + result = new CreatePrincipalResult(principal, password, keyNumber); + message = String.format("Successfully set password for %s", principal); + LOG.debug(message); + } else { + message = String.format("Failed to set password for %s - unknown reason", principal); + LOG.error(message); + if (actionLog != null) { + actionLog.writeStdErr(message); + } + } } else { - message = String.format("Failed to create principal, %s - unknown reason", principal); - LOG.error(message); - if (actionLog != null) { - actionLog.writeStdErr(message); + message = String.format("Creating new principal, %s", principal); + LOG.debug(message); + + Integer keyNumber = kerberosOperationHandler.createPrincipal(principal, password, isServicePrincipal); + + if (keyNumber != null) { + result = new CreatePrincipalResult(principal, password, keyNumber); + message = String.format("Successfully created new principal, %s", principal); + LOG.debug(message); + } else { + message = String.format("Failed to create principal, %s - unknown reason", principal); + LOG.error(message); + if (actionLog != null) { + actionLog.writeStdErr(message); + } } } - } - if (!kerberosPrincipalDAO.exists(principal)) { - kerberosPrincipalDAO.create(principal, isServicePrincipal); - } + if (!kerberosPrincipalDAO.exists(principal)) { + kerberosPrincipalDAO.create(principal, isServicePrincipal); + } - } catch (KerberosOperationException e) { - message = String.format("Failed to create principal, %s - %s", principal, e.getMessage()); - LOG.error(message, e); - if (actionLog != null) { - actionLog.writeStdErr(message); + } catch (KerberosOperationException e) { + message = String.format("Failed to create principal, %s - %s", principal, e.getMessage()); + LOG.error(message, e); + if (actionLog != null) { + actionLog.writeStdErr(message); + } + } + } finally { + if(result == null) { + auditEventBuilder.withReasonOfFailure(message == null ? "Unknown error" : message); } + auditLog(auditEventBuilder.build()); } return result; http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java index 93daae8..ce46af4 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java @@ -21,8 +21,10 @@ package org.apache.ambari.server.serveraction.kerberos; import com.google.inject.Inject; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.agent.CommandReport; +import org.apache.ambari.server.audit.kerberos.DestroyPrincipalKerberosAuditEvent; import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO; import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity; +import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,35 +91,44 @@ public class DestroyPrincipalsServerAction extends KerberosServerAction { String message = String.format("Destroying identity, %s", evaluatedPrincipal); LOG.info(message); actionLog.writeStdOut(message); + DestroyPrincipalKerberosAuditEvent.DestroyPrincipalKerberosAuditEventBuilder auditEventBuilder = DestroyPrincipalKerberosAuditEvent.builder() + .withTimestamp(DateTime.now()) + .withPrincipal(evaluatedPrincipal); try { - operationHandler.removePrincipal(evaluatedPrincipal); - } catch (KerberosOperationException e) { - message = String.format("Failed to remove identity for %s from the KDC - %s", evaluatedPrincipal, e.getMessage()); - LOG.warn(message); - actionLog.writeStdErr(message); - } - try { - KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal); + try { + operationHandler.removePrincipal(evaluatedPrincipal); + } catch (KerberosOperationException e) { + message = String.format("Failed to remove identity for %s from the KDC - %s", evaluatedPrincipal, e.getMessage()); + LOG.warn(message); + actionLog.writeStdErr(message); + auditEventBuilder.withReasonOfFailure(message); + } - if(principalEntity != null) { - String cachedKeytabPath = principalEntity.getCachedKeytabPath(); + try { + KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal); - kerberosPrincipalDAO.remove(principalEntity); + if (principalEntity != null) { + String cachedKeytabPath = principalEntity.getCachedKeytabPath(); - // If a cached keytabs file exists for this principal, delete it. - if (cachedKeytabPath != null) { - if (!new File(cachedKeytabPath).delete()) { - LOG.debug(String.format("Failed to remove cached keytab for %s", evaluatedPrincipal)); + kerberosPrincipalDAO.remove(principalEntity); + + // If a cached keytabs file exists for this principal, delete it. + if (cachedKeytabPath != null) { + if (!new File(cachedKeytabPath).delete()) { + LOG.debug(String.format("Failed to remove cached keytab for %s", evaluatedPrincipal)); + } } } + } catch (Throwable t) { + message = String.format("Failed to remove identity for %s from the Ambari database - %s", evaluatedPrincipal, t.getMessage()); + LOG.warn(message); + actionLog.writeStdErr(message); + auditEventBuilder.withReasonOfFailure(message); } - } - catch (Throwable t) { - message = String.format("Failed to remove identity for %s from the Ambari database - %s", evaluatedPrincipal, t.getMessage()); - LOG.warn(message); - actionLog.writeStdErr(message); + } finally { + auditLog(auditEventBuilder.build()); } // There is no reason to fail this task if an identity was not removed. The cluster will work http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java index c710b8e..55b1fbb 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java @@ -21,11 +21,13 @@ package org.apache.ambari.server.serveraction.kerberos; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.actionmanager.HostRoleStatus; import org.apache.ambari.server.agent.CommandReport; +import org.apache.ambari.server.audit.kerberos.ChangeSecurityStateKerberosAuditEvent; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Host; import org.apache.ambari.server.state.SecurityState; import org.apache.ambari.server.state.ServiceComponentHost; import org.apache.commons.io.FileUtils; +import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -91,6 +93,14 @@ public class FinalizeKerberosServerAction extends KerberosServerAction { actionLog.writeStdOut(message); sch.setSecurityState(sch.getDesiredSecurityState()); + ChangeSecurityStateKerberosAuditEvent auditEvent = ChangeSecurityStateKerberosAuditEvent.builder() + .withTimestamp(DateTime.now()) + .withService(sch.getServiceName()) + .withComponent(sch.getServiceComponentName()) + .withHostName(sch.getHostName()) + .withState(sch.getDesiredSecurityState().toString()) + .build(); + auditLog(auditEvent); } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/a885ef5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java index 90d9414..6ff6069 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java @@ -19,6 +19,7 @@ package org.apache.ambari.server.serveraction.kerberos; import com.google.inject.Inject; + import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.actionmanager.HostRoleStatus; import org.apache.ambari.server.agent.CommandReport;