Пример #1
0
  public Json makeTyped(Object anything) {
    boolean isarray = anything.getClass().isArray();
    Class<?> type = isarray ? anything.getClass().getComponentType() : anything.getClass();
    JsonConverter converter = converterMap.get(type.getName());
    String typeName = shortNameMap.getY(type.getName());
    if (typeName == null) typeName = type.getName();
    if (isarray) {
      Json result = Json.array();
      Object[] A = (Object[]) anything;
      for (Object x : A) {
        if (x == null) result.add(Json.nil());
        else result.add(converter != null ? converter.to(x) : make(x));
      }
      return Json.object().set("javaArrayType", typeName).set("array", result);
    } else if (type.isEnum())
      return Json.object().set("java.lang.Enum", type.getName()).set("value", anything.toString());

    for (Class<?> abstractConv : converterFromAbstractMap.keySet())
      if (abstractConv.isAssignableFrom(type))
        return converterFromAbstractMap.get(abstractConv).to(anything);
    Json value = null;
    if (converter != null) value = converter.to(anything);
    else if (Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type))
      value = beanConverter.to(anything);
    else
      try {
        value = f.make(anything);
      } catch (Throwable t) {
        value = beanConverter.to(anything);
      }
    return Json.object().set("javaType", typeName).set("value", value);
  }
Пример #2
0
 public Json to(Object x) {
   String typeName =
       shortNameMap.containsX(x.getClass().getName())
           ? shortNameMap.getY(x.getClass().getName())
           : x.getClass().getName();
   Json result = Json.object().set("javaType", typeName);
   if (x instanceof HGLink) {
     result.set("_link", array());
     for (int i = 0; i < ((HGLink) x).getArity(); i++)
       result.at("_link").add(((HGLink) x).getTargetAt(i));
   }
   if (x instanceof Collection) {
     result.set("_collection", array());
     for (Object element : (Collection<?>) x)
       result.at("_collection").add(makeProperty(element));
   }
   if (x instanceof Map) {
     result.set("_map", array());
     for (Map.Entry<?, ?> e : ((Map<?, ?>) x).entrySet())
       result
           .at("_map")
           .add(
               Json.object()
                   .set("key", makeProperty(e.getKey()))
                   .set("value", makeProperty(e.getValue())));
   }
   try {
     if (props != null) // user provided list of properties
     for (String propname : props) {
         PropertyDescriptor desc = BonesOfBeans.getPropertyDescriptor(x, propname);
         Object value = BonesOfBeans.getProperty(x, desc);
         if (!ignoreNulls || value != null) result.set(propname, makeProperty(value));
       }
     else // all introspected properties
     for (PropertyDescriptor desc : BonesOfBeans.getAllPropertyDescriptors(x).values())
         if (desc.getReadMethod() != null && desc.getWriteMethod() != null) {
           Object value = BonesOfBeans.getProperty(x, desc);
           if (!ignoreNulls || value != null) result.set(desc.getName(), makeProperty(value));
         }
     return result;
   } catch (Throwable ex) {
     HGUtils.throwRuntimeException(ex);
   }
   return null; // unreachable
 }
Пример #3
0
 /**
  * Retrieve full user information given a user id (a.k.a. username). If there are multiple user
  * backing stores configured, information from each will be aggregated. The provider with the
  * highest priority will be used to provide based information, but then each separate provider is
  * added as a property.
  *
  * <p>For example, if you have an LDAP provider called "ldap" and a databse provider called "db",
  * with the ldap provider being the default (high priority), you would get something that looks
  * like <code>{ "hasUsername":id, "FirstName":"John",
  * "ldap":{...all LDAP user attributes }, "db":{ all DB user attributes}}</code>
  *
  * @param id
  * @return
  */
 @GET
 @Path("{id}")
 @Produces("application/json")
 public Json getUserById(@PathParam("id") String id) {
   Json user = Json.object("userid", id);
   List<String> plist = orderedProviders();
   for (String providerName : plist) {
     UserProvider P = provider(providerName);
     P.populate(user);
   }
   return ok().set("profile", prepareReturn(user));
 }
Пример #4
0
 private List<String> orderedProviders() {
   ArrayList<String> L =
       new ArrayList<String>(desc.at("hasUserBase", Json.object()).asJsonMap().keySet());
   Collections.sort(
       L,
       new Comparator<String>() {
         public int compare(String left, String right) {
           int x = desc.at("hasUserBase").at(left).at("hasOrdinal", Integer.MAX_VALUE).asInteger();
           int y =
               desc.at("hasUserBase").at(right).at("hasOrdinal", Integer.MAX_VALUE).asInteger();
           return x - y;
         }
       });
   return L;
 }
Пример #5
0
 @GET
 @Path("search")
 public Json search(
     @QueryParam("id") String id,
     @QueryParam("name") String searchString,
     @QueryParam("providers") String providers) {
   if (id != null && !id.isEmpty()) {
     return Json.array().add(searchUserById(id));
   }
   Json resultList = Json.array();
   final int maxResults = 15;
   try {
     if (searchString == null || searchString.length() == 0) return null;
     else searchString = searchString.trim();
     Json user = Json.object();
     String name = searchString;
     name = name.trim();
     int idx;
     // Parse search string
     if ((idx = name.indexOf(',')) > -1) { // Miller, Bob
       user.set("LastName", name.substring(0, idx).trim());
       user.set("FirstName", name.substring(idx + 1).trim());
     } else if ((idx = name.indexOf(' ')) > -1) { // Bob Miller
       user.set("LastName", name.substring(idx + 1).trim());
       user.set("FirstName", name.substring(0, idx).trim());
     } else { // Miller
       user.set("LastName", name);
     }
     if (user.is("FirstName", "")) user.delAt("FirstName");
     if (user.is("LastName", "")) user.delAt("LastName");
     if (user.asJsonMap().size() > 0) {
       Collection<String> P =
           providers != null ? Arrays.asList(providers.split(",")) : orderedProviders();
       for (String providerName : P)
         resultList.with(searchProvider(providerName, user, maxResults));
     }
   } catch (Exception e) {
     e.printStackTrace();
     return ko(e);
   }
   return prepareReturn(resultList);
 }
Пример #6
0
/**
 * Main entry point for user management - authentication, profile retrieval, access policies.
 *
 * @author Syed Abbas
 * @author Tom Hilpold
 * @author Borislav Iordanov
 */
@Path("users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserService extends RestService implements AutoConfigurable {
  public static final IRI DEFAULT_STOP_EXPANSION_CONDITION_IRI1 = Model.upper("Department");
  public static final IRI DEFAULT_STOP_EXPANSION_CONDITION_IRI2 = Model.upper("Divison");
  public static final IRI DEFAULT_STOP_EXPANSION_CONDITION_IRI3 = Model.upper("hasDivision");
  public static final IRI DEFAULT_STOP_EXPANSION_CONDITION_IRI4 = Model.upper("hasObject");
  public static final String CIRM_ADMIN = Model.upper("CirmAdmin").toString();

  private final OWLObjectPropertyCondition stopExpansionCondition = getStopExpansionCondition();

  private OWLObjectPropertyCondition getStopExpansionCondition() {
    Set<OWLObjectProperty> stopExpansionProps = new HashSet<OWLObjectProperty>();
    stopExpansionProps.add(OWL.objectProperty(DEFAULT_STOP_EXPANSION_CONDITION_IRI1));
    stopExpansionProps.add(OWL.objectProperty(DEFAULT_STOP_EXPANSION_CONDITION_IRI2));
    stopExpansionProps.add(OWL.objectProperty(DEFAULT_STOP_EXPANSION_CONDITION_IRI3));
    stopExpansionProps.add(OWL.objectProperty(DEFAULT_STOP_EXPANSION_CONDITION_IRI4));
    return new OWLObjectPropertyCondition(stopExpansionProps);
  }

  private Json desc = Json.object();
  private static volatile Map<String, UserProvider> providerMap =
      new HashMap<String, UserProvider>();

  private List<String> orderedProviders() {
    ArrayList<String> L =
        new ArrayList<String>(desc.at("hasUserBase", Json.object()).asJsonMap().keySet());
    Collections.sort(
        L,
        new Comparator<String>() {
          public int compare(String left, String right) {
            int x = desc.at("hasUserBase").at(left).at("hasOrdinal", Integer.MAX_VALUE).asInteger();
            int y =
                desc.at("hasUserBase").at(right).at("hasOrdinal", Integer.MAX_VALUE).asInteger();
            return x - y;
          }
        });
    return L;
  }

  private String authenticateProvider() {
    return desc.at("authenticatesWith").at("hasName").asString();
  }

  private UserProvider provider(String name) {
    synchronized (providerMap) {
      UserProvider provider = providerMap.get(name);
      if (provider != null) return provider;
      if (!desc.at("hasUserBase").has(name)) return null;
      String classname =
          desc.at("hasUserBase")
              .at(name)
              .at("hasImplementation")
              .at("iri")
              .asString()
              .split("#")[1];
      try {
        provider = (UserProvider) Class.forName(classname).newInstance();
        // Autoconfigure is not part of the object initialisation
        // without synchronization, variables set during autoconfigure might not be readable by
        // other threads.
        synchronized (provider) {
          if (provider instanceof AutoConfigurable)
            ((AutoConfigurable) provider).autoConfigure(desc.at("hasUserBase").at(name));
        }
        providerMap.put(name, provider);
        return provider;
      } catch (Exception ex) {
        throw new RuntimeException(ex);
      }
    }
  }

  private Json getAccessPolicies(Json groups) {
    if (!groups.isArray())
      throw new IllegalArgumentException("Expected Array of cirmusergroups. e.g. legacy:311..");
    Json cirmUserGroupsWithAccessPolicies = Json.array();
    for (Json iri : groups.asJsonList()) {
      OWLIndividual group = dataFactory().getOWLNamedIndividual(fullIri(iri.asString()));
      // Here we need to make sure that the serialization stops at e.g.
      // individuals that are the objects of an AccessPolicy!
      Json groupWithAccessPolicies = OWL.toJSON(group, stopExpansionCondition);
      cirmUserGroupsWithAccessPolicies.add(groupWithAccessPolicies);
    }
    // Array of cirm groups with all access policy information serialized.
    return cirmUserGroupsWithAccessPolicies; // userdata.set("cirmusergroups",
                                             // cirmUserGroupsWithAccessPolicies);
  }

  private Json prepareReturn(Json user) {
    if (user.isArray()) {
      for (Json u : user.asJsonList()) prepareReturn(u);
    } else {
      user.delAt("hasPassword");
      // TODO: can we get rid of this? the fear that somewhere on the client
      // it is being used, but it shouldn't be.
      if (user.has("hasUsername")) user.set("username", user.at("hasUsername"));
    }
    return user;
  }

  public void autoConfigure(Json config) {
    this.desc = config;
  }

  /**
   * This is a general method to retrieve information about a particular user. Because it's
   * expensive to fill out all information we can get about a user, the request is a more complex
   * object that specifies what is to be provided. In this way, a client can request all that is
   * needed and only that which is needed in a single network round-trip.
   *
   * <p>The basic profile (first name, email etc.) is returned regardless. Here are the expected
   * properties of the JSON <code>request</code> parameter that control what else is returned:
   *
   * <ul>
   *   <li>username - mandatory...of course
   *   <li>groups - true/false whether to include the list of groups the user belongs to
   *   <li>access - true/false whether to include the access policies for this user
   * </ul>
   *
   * @param request
   * @return
   */
  @POST
  @Path("/profile")
  public Json userProfile(Json request) {
    try {
      if (!request.isObject() || !request.has("username")) return ko("bad request.");
      if (!request.has("provider") || request.is("provider", ""))
        request.set("provider", desc.at("authenticatesWith").at("hasName"));
      UserProvider providerImpl = provider(request.at("provider").asString());
      Json profile = providerImpl.get(request.at("username").asString());
      if (profile.isNull()) return ko("No profile");
      if (request.is("groups", true) || request.is("access", true))
        profile.set("groups", providerImpl.findGroups(request.at("username").asString()));
      if (request.is("access", true))
        profile.set("access", getAccessPolicies(profile.at("groups")));
      return ok().set("profile", prepareReturn(profile));
    } catch (Throwable t) {
      if (!"unavailable"
          .equals(t.getMessage())) // error would have already been reported in the logs
      t.printStackTrace(System.err);
      return ko(t.getMessage());
    }
  }

  /**
   * Authenticate within a given realm (user provider).
   *
   * @param form
   * @return
   */
  @POST
  @Path("/authenticate")
  public Json authenticate(Json form) {
    if (!form.has("provider") || form.is("provider", ""))
      form.set("provider", desc.at("authenticatesWith").at("hasName"));
    if (form.is("provider", authenticateProvider())) {
      if (!form.has("password") || form.is("password", "")) return ko("Please provide a password.");
      Json userdata = userProfile(form);
      if (userdata.is("error", "No profile")) return ko("User not found or invalid password.");
      else if (!userdata.is("ok", true)) return userdata;
      else if (!StartUp.getConfig().is("ignorePasswords", true)) {
        if (!provider(form.at("provider").asString())
            .authenticate(
                userdata.at("profile").at("hasUsername").asString(),
                form.at("password").asString())) return ko("User not found or invalid password.");
      }
      if (dbg()) {
        String msg =
            (userdata.at("profile").has("hasUsername"))
                ? userdata.at("profile").at("hasUsername").asString()
                : "Unknown";
        msg += " | lastname: " + (userdata.at("profile").at("lastName", " no lastname")).toString();
        msg +=
            "\r\n | groups: "
                + (userdata.at("profile").at("groups", " no groups")).toString()
                + "\r\n";
        ThreadLocalStopwatch.getWatch().time("Auth success: " + msg);
        ThreadLocalStopwatch.dispose();
      }
      return ok().set("user", prepareReturn(userdata.at("profile")));
    }
    // other realms/providers...
    else return ko("Unknown realm");
  }

  /**
   * Consumes an array of group names and augments those groups with the corresponding access
   * policies.
   *
   * @param groups An array of names of groups.
   * @return
   */
  @POST
  @Path("/accesspolicies")
  public Json accessPolicies(Json groups) {
    groups = getAccessPolicies(groups);
    if (!groups.asList().isEmpty() && groups.at(0).has("hasAccessPolicy"))
      return ok().set("cirmusergroups", groups);
    else return ko("No Access policies are available for user.");
  }

  @GET
  @Path("search")
  public Json search(
      @QueryParam("id") String id,
      @QueryParam("name") String searchString,
      @QueryParam("providers") String providers) {
    if (id != null && !id.isEmpty()) {
      return Json.array().add(searchUserById(id));
    }
    Json resultList = Json.array();
    final int maxResults = 15;
    try {
      if (searchString == null || searchString.length() == 0) return null;
      else searchString = searchString.trim();
      Json user = Json.object();
      String name = searchString;
      name = name.trim();
      int idx;
      // Parse search string
      if ((idx = name.indexOf(',')) > -1) { // Miller, Bob
        user.set("LastName", name.substring(0, idx).trim());
        user.set("FirstName", name.substring(idx + 1).trim());
      } else if ((idx = name.indexOf(' ')) > -1) { // Bob Miller
        user.set("LastName", name.substring(idx + 1).trim());
        user.set("FirstName", name.substring(0, idx).trim());
      } else { // Miller
        user.set("LastName", name);
      }
      if (user.is("FirstName", "")) user.delAt("FirstName");
      if (user.is("LastName", "")) user.delAt("LastName");
      if (user.asJsonMap().size() > 0) {
        Collection<String> P =
            providers != null ? Arrays.asList(providers.split(",")) : orderedProviders();
        for (String providerName : P)
          resultList.with(searchProvider(providerName, user, maxResults));
      }
    } catch (Exception e) {
      e.printStackTrace();
      return ko(e);
    }
    return prepareReturn(resultList);
  }

  /**
   * Searches a user by ID. If multiple realms are configured, each will be tried according to their
   * ordinal number configuration. Only the first found is returned.
   */
  public Json searchUserById(String id) {
    if (id == null || id.length() == 0) return Json.array();
    for (String providerName : orderedProviders()) {
      UserProvider P = provider(providerName);
      Json user = P.get(id);
      if (!user.isNull()) return user;
    }
    return Json.nil();
  }

  public Json searchProvider(String name, Json prototype, int maxResults) {
    UserProvider provider = provider(name);
    if (provider == null) throw new RuntimeException("Unknown user realm " + name);
    return provider.find(prototype, maxResults);
  }

  @GET
  @Path("{provider}/{id}")
  @Produces("application/json")
  public Json getUserJson(
      @PathParam(value = "provider") String provider, @PathParam(value = "id") String id) {
    UserProvider providerImpl = provider(provider);
    if (providerImpl == null) return ko("Unknown realm " + provider);
    return prepareReturn(providerImpl.get(id));
  }

  /**
   * Retrieve full user information given a user id (a.k.a. username). If there are multiple user
   * backing stores configured, information from each will be aggregated. The provider with the
   * highest priority will be used to provide based information, but then each separate provider is
   * added as a property.
   *
   * <p>For example, if you have an LDAP provider called "ldap" and a databse provider called "db",
   * with the ldap provider being the default (high priority), you would get something that looks
   * like <code>{ "hasUsername":id, "FirstName":"John",
   * "ldap":{...all LDAP user attributes }, "db":{ all DB user attributes}}</code>
   *
   * @param id
   * @return
   */
  @GET
  @Path("{id}")
  @Produces("application/json")
  public Json getUserById(@PathParam("id") String id) {
    Json user = Json.object("userid", id);
    List<String> plist = orderedProviders();
    for (String providerName : plist) {
      UserProvider P = provider(providerName);
      P.populate(user);
    }
    return ok().set("profile", prepareReturn(user));
  }

  public String getFullName(String userid) {
    if (userid == null || userid.isEmpty()) return "";
    Json user = searchUserById(userid);
    if (user.isNull()) return "";
    else return user.at("FirstName", "").asString() + " " + user.at("LastName", "").asString();
  }

  public UserService() {
    autoConfigure(Refs.owlJsonCache.resolve().individual(OWL.fullIri("UserService")).resolve());
  }
}
Пример #7
0
 public Json to(Object x) {
   Json result = Json.object().set("javaType", x.getClass().getName()).set("data", array());
   for (Object item : (Collection<?>) x) result.at("data").add(make(item));
   return result;
 }
Пример #8
0
 public Json to(Object x) {
   return Json.object()
       .set("javaType", HGIndex.class.getName())
       .set("value", ((HGIndex<?, ?>) x).getName());
 }