EMMA Coverage Report (generated Wed Jun 22 19:47:49 EDT 2011)
[all classes][org.jclouds.scriptbuilder.statements.login]

COVERAGE SUMMARY FOR SOURCE FILE [ReplaceShadowPasswordEntry.java]

nameclass, %method, %block, %line, %
ReplaceShadowPasswordEntry.java100% (1/1)50%  (3/6)58%  (87/151)42%  (15/36)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ReplaceShadowPasswordEntry100% (1/1)50%  (3/6)58%  (87/151)42%  (15/36)
equals (Object): boolean 0%   (0/1)0%   (0/37)0%   (0/13)
functionDependencies (OsFamily): Iterable 0%   (0/1)0%   (0/2)0%   (0/1)
hashCode (): int 0%   (0/1)0%   (0/19)0%   (0/4)
render (OsFamily): String 100% (1/1)91%  (64/70)73%  (8/11)
ReplaceShadowPasswordEntry (String, String): void 100% (1/1)100% (18/18)100% (5/5)
cryptFunction (Function): ReplaceShadowPasswordEntry 100% (1/1)100% (5/5)100% (2/2)

1/**
2 *
3 * Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
4 *
5 * ====================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 * ====================================================================
18 */
19package org.jclouds.scriptbuilder.statements.login;
20 
21import static com.google.common.base.Preconditions.checkNotNull;
22import static com.google.common.base.Throwables.propagate;
23import static java.lang.String.format;
24import static org.jclouds.scriptbuilder.domain.Statements.exec;
25 
26import javax.inject.Named;
27 
28import org.jclouds.crypto.Sha512Crypt;
29import org.jclouds.scriptbuilder.domain.OsFamily;
30import org.jclouds.scriptbuilder.domain.Statement;
31import org.jclouds.scriptbuilder.domain.StatementList;
32 
33import com.google.common.annotations.VisibleForTesting;
34import com.google.common.base.Function;
35import com.google.common.collect.ImmutableList;
36import com.google.inject.Inject;
37 
38/**
39 * Replaces the password entry for a user in the shadow file, using SHA-512
40 * crypt syntax.
41 * 
42 * @author Adrian Cole
43 */
44public class ReplaceShadowPasswordEntry implements Statement {
45 
46   private final String login;
47   private final String password;
48 
49   private Function<String, String> cryptFunction = Sha512Crypt.function();
50 
51   @Inject(optional = true)
52   @Named("CRYPT")
53   @VisibleForTesting
54   ReplaceShadowPasswordEntry cryptFunction(Function<String, String> cryptFunction) {
55      this.cryptFunction = cryptFunction;
56      return this;
57   }
58 
59   public ReplaceShadowPasswordEntry(String login, String password) {
60      this.login = checkNotNull(login, "login");
61      this.password = checkNotNull(password, "password");
62   }
63 
64   @Override
65   public Iterable<String> functionDependencies(OsFamily family) {
66      return ImmutableList.of();
67   }
68 
69   @Override
70   public String render(OsFamily family) {
71      checkNotNull(family, "family");
72      if (family == OsFamily.WINDOWS)
73         throw new UnsupportedOperationException("windows not yet implemented");
74      try {
75         String shadowPasswordEntry = cryptFunction.apply(password);
76         String shadowFile = "/etc/shadow";
77         // note we are using awk variables so that the user can be defined as a
78         // shell variable (ex. $USER) As the block is in single quotes,
79         // shell interpolation wouldn't work otherwise
80         Statement replaceEntryInTempFile = exec(format(
81               "awk -v user=^%1$s: -v password='%2$s' 'BEGIN { FS=OFS=\":\" } $0 ~ user { $2 = password } 1' %3$s >%3$s.%1$s",
82               login, shadowPasswordEntry, shadowFile));
83         // would have preferred to use exec <>3 && style, but for some reason
84         // the sha512 line breaks in both awk and sed during an inline
85         // expansion. unfortunately, we have to save a temp file. In this case,
86         // somewhat avoiding collisions by naming the file .user, conceding it
87         // isn't using any locks to prevent overlapping changes
88         Statement replaceShadowFile = exec(format("test -f %2$s.%1$s && mv %2$s.%1$s %2$s", login, shadowFile));
89         return new StatementList(ImmutableList.of(replaceEntryInTempFile, replaceShadowFile)).render(family);
90      } catch (Exception e) {
91         propagate(e);
92         return null;
93      }
94   }
95 
96   @Override
97   public int hashCode() {
98      final int prime = 31;
99      int result = 1;
100      result = prime * result + ((login == null) ? 0 : login.hashCode());
101      return result;
102   }
103 
104   @Override
105   public boolean equals(Object obj) {
106      if (this == obj)
107         return true;
108      if (obj == null)
109         return false;
110      if (getClass() != obj.getClass())
111         return false;
112      ReplaceShadowPasswordEntry other = (ReplaceShadowPasswordEntry) obj;
113      if (login == null) {
114         if (other.login != null)
115            return false;
116      } else if (!login.equals(other.login))
117         return false;
118      return true;
119   }
120}

[all classes][org.jclouds.scriptbuilder.statements.login]
EMMA 2.0.5312 (C) Vladimir Roubtsov