2012-05-01 1 views
4

я использую Гобелен-Security, которая использует Apache ShiroShiro авторизации заселить авторизации с удаленными ролями

У меня есть пользовательская область, которая обрабатывает авторизацию и аутентификацию. Наша аутентификация технически происходит с использованием удаленной службы, которая возвращает имя пользователя и набор ролей. Я просто передаю имя пользователя в свой собственный AuthenticationToken, который позволяет мне запрашивать наш локальный db и устанавливать SimpleAuthenticationInfo.

Я не могу понять, как заполнить метод AuthorizationInfo doGetAuthorizationInfo, используя список ролей, возвращенных мне из нашей удаленной службы. Ниже приведен код, который я использую для заполнения области.

Login.class

//Remote authentication service 
RemoteLoginClient client = new RemoteLoginClient(); 
RemoteSubject authenticate = client.authenticate(username, password); 

//tapestry security authentication 
Subject currentUser = SecurityUtils.getSubject(); 
CustomAuthenticationToken token = new 
    CustomAuthenticationToken(authenticate.getUsername()); 
System.out.println("roles" + authenticate.getRoles()); 

currentUser.login(token); 

метод AuthorizationInfo внутри customRealm общественного класс CustomRealm расширяет AuthorizingRealm {

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 
    CustomAuthenticationToken upToken = (CustomAuthenticationToken) token; 
    String email = upToken.getUsername(); 

    ApplicationUser applicationUser = (ApplicationUser) session.createCriteria(ApplicationUser.class) 
      .add(Restrictions.like("email", email + "%")) 
      .uniqueResult(); 

    if (applicationUser == null) { 
     throw new UnknownAccountException("User doesn't exist in EPRS database"); 
    } 

    return buildAuthenticationInfo(applicationUser.getId()); 
} 

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 
//Not sure how to populate the principle or 
//read the principle to populate the SimpleAuthorizationInfo 
    return new SimpleAuthorizationInfo(roleNames); 
} 
+0

Несколько недель назад я записывала, как бороться с Сиро и Guice. Однако не могли бы вы проверить, будет ли в разделе «Реализация королевств» ваш вопрос - http://readyareyou.blogspot.de/2012/03/guice-jersey-shiro.html? – PepperBob

+0

@PepperBob Спасибо за ответ, мне кажется, пример в ссылке, которую вы мне предоставили, все еще использует базу данных для поиска ролей пользователей. В моем сценарии роли предоставляются мне в списке из нашего веб-сервиса при входе в систему. Я бы хотел, чтобы передать этот список ролей в SimpleAuthorizationInfo, где я сейчас потерян. Какие-нибудь дополнительные мысли? –

+0

Я думаю, что вы должны быть в состоянии вставить все в реализацию интерфейса учетной записи (http://shiro.apache.org/static/current/apidocs/org/apache/shiro/authc/Account.html), поскольку он связывает Аутентификация и авторизация, например. SimpleAccount или что-то сделанное на заказ. – PepperBob

ответ

6

Расширение AuthorizingRealm является хорошим местом для начала, если вам нужна как аутентификация и авторизация. Кроме того, как уже сказал PepperBob, в то время как вы на нем, интерфейс Account и его реализация SimpleAccount поддерживают как аутентификацию, так и авторизацию в одном интерфейсе, поэтому вам не нужно особого кода для doGetAuthenticationInfo() и doGetAuthorizationInfo() и может просто вернуть тот же объект из обоих методов.

Чтобы получить информацию авторизации, вам нужно сделать две вещи:

  • Получить доступную принципала из основной коллекции, переданной в качестве параметра (который, в большинстве случаев, только содержит один главный в любом случае) через getAvailablePrincipal() метод (аккуратно предопределено в AuthorizingRealm).
  • Загрузите свои роли и передайте их setRoles() в свой аккаунт.

... и все готово.

Edited добавить:

Это было бы очень простой способ для хранения роли, пока они вам не нужны. Обратите внимание, что фактическая аутентификация выполняется в области, которая имеет зависимость от RemoteLoginClient.

public class MyRealm extends AuthorizingRealm { 

    private RemoteLoginClient client = ...; 

    private final Map<String, Set<String>> emailToRoles = new ConcurrentHashMap<>(); 

    @Override 
    protected AuthenticationInfo doGetAuthenticationInfo(
      AuthenticationToken token) { 
     final UsernamePasswordToken userPass = (UsernamePasswordToken) token; 

     final RemoteSubject authenticate = this.client.authenticate(
      userPass.getUserName(), userPass.getPassword()); 
     if (authenticate != null) { //assuming this means success 
      this.emailToRoles.put(userPass.getUserName(), authenticate.getRoles()); 
      return new SimpleAuthenticationInfo(...); 
     } else { 
      return null; 
     } 
    } 

    @Override 
    protected AuthorizationInfo doGetAuthorizationInfo(
      PrincipalCollection principals) { 
     final String username = (String) principals.getPrimaryPrincipal(); 
     final Set<String> roles = this.emailToRoles.get(username); 
     return new SimpleAuthorizationInfo(roles); 
    } 

} 
+0

Привет Хеннинг, я не уверен, что ваше предложение отвечает на мой вопрос. Я отправил мой метод doGetAuthenticationInfo выше. В публикации в списке рассылки для широкой публики Les Hazelwood предлагает вам предварительно создать и кэшировать объект AuthorizationInfo во время проверки подлинности, так что во время входа в систему есть только один «хит». Вы сделали бы это, вызвав метод getAuthorizationInfo (PrincipalCollection Principals) из вашего метода doGetAuthenticationInfo. Я не уверен, как это можно проверить здесь. Http://shiro-user.582556.n2.nabble.com/Shiro-and-LDAP-authorization-td7096956.html#a7520967 Спасибо –

+0

В этом случае я не знаю, Думаю, я полностью понял этот вопрос. Итак, вам нужно сделать аутентификацию и авторизацию за один шаг, потому что ваш бэкенд требует этого? Да, вам придется кэшировать роли, принадлежащие пользователю, это правильно. В чем именно проблема, с которой вы сталкиваетесь? Разве вы не можете понять, как их хранить, чтобы вы могли вернуть их в 'doGetAuthorizationInfo()'? Если да, почему бы просто не поставить их на карту, когда вы попали в бэкэнд? – Henning

+0

Я только что опубликовал рабочее решение. Если бы вы взглянули на него, вы увидите, чего я пытаюсь выполнить. Не стесняйтесь предлагать предложения. Я никоим образом не специалист по Shiro, поэтому я уверен, что есть возможности для улучшения. Спасибо Хеннинг. –

3

Я ответил на свой вопрос и хотел опубликовать его на случай, если кому-то понадобится помощь или возможное улучшение моего решения.

метод Login.class

Object onSubmit() { 
    try { 
     //Remote Authentication 
     RemoteLoginClient client = new RemoteLoginClient(); 
     RemoteSubject authenticate = client.authenticate(formatUsername(username), password); 

     //tapestry security authentication 
     Subject currentUser = SecurityUtils.getSubject(); 
     CustomAuthenticationToken token = new CustomAuthenticationToken(authenticate.getUsername(), authenticate.getRoles()); 

     currentUser.login(token); 
    } //catch errors 
} 

// Пользовательский маркер, используемый для хранения имени пользователя и роли, которые устанавливаются с удаленной службы аутентификации.

public class CustomAuthenticationToken implements AuthenticationToken { 

private String username; 
private Set<String> roles; 

public CustomAuthenticationToken(String username, Set<String> roles) { 
    this.username = username; 
    this.roles = roles; 
} 

getters/setters 

// Пользовательское царство используется для обработки локальной аутентификации и авторизации.

public class CustomRealm extends AuthorizingRealm { 

//Hibernate Session 
private final Session session; 
public static final String EMPTY_PASSWORD = ""; 

public CustomRealm(Session session) { 
    this.session = session; 
    setCredentialsMatcher(new AllowAllCredentialsMatcher()); 
    setAuthenticationTokenClass(CustomAuthenticationToken.class); 
} 

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 
    CustomAuthenticationToken customToken = (CustomAuthenticationToken) token; 
    String email = customToken.getUsername(); 

    User user = (User) session.createCriteria(User.class) 
      .add(Restrictions.like("email", email+ "%")) 
      .uniqueResult(); 

    if (user == null) { 
     throw new UnknownAccountException("User doesn't exist in local database"); 
    } 

    return new SimpleAuthenticationInfo(new CustomPrincipal(user, customToken.getRoles()), EMPTY_PASSWORD, getName()); 
} 

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 
    return new SimpleAuthorizationInfo(((CustomPrincipal) principals.getPrimaryPrincipal()).getRoles()); 
} 

}

// Пользовательский основной используется для хранения объекта пользователя и роли общественного класса CustomPrincipal {

private User user; 
private Set<String> roles; 

public CustomPrincipal() { 
} 

public CustomPrincipal(User user, Set<String> roles) { 
    this.user = user; 
    this.roles = roles; 
} 

getters/setters