Menambahkan Otoritas di AuthenticationSuccessHandler

Saya sedang bekerja dengan situs web Spring MVC dan menambahkan otentikasi dengan Direktori Aktif melalui LDAP. Perusahaan tidak ingin menggunakan otoritas AD untuk memetakan izin situs web, kami memiliki database yang mencantumkan setiap izin pengguna, jadi saya mencoba menyambungkannya, mendapatkan izin, dan menambahkannya ke token Otentikasi pengguna.

Ketika saya pertama kali memulai, saya memetakan otoritas kelompok pengguna AD dengan GrantedAuthoritiesMapper dan itu berhasil. Itu terlihat seperti ini:

public class ActiveDirectoryGrantedAuthoritiesMapper implements GrantedAuthoritiesMapper {

    private static final String ROLE_ADMIN = "adminUserGroup";

    public ActiveDirectoryGrantedAuthoritiesMapper()
    { }

    public Collection<? extends GrantedAuthority> mapAuthorities(
            final Collection<? extends GrantedAuthority> authorities)
    {

        Set<CustomAuthority> roles = EnumSet.noneOf(CustomAuthority.class);

        for (GrantedAuthority authority : authorities)
        {
            if (ROLE_ADMIN.equals(authority.getAuthority()))
            {
                roles.add(CustomAuthority.ROLE_ADMIN);
            }
            //Default role for all users.
            roles.add(CustomAuthority.ROLE_EMPLOYEE);
        }
        return roles;
    }
}

Sekarang saya mencoba mengonversinya untuk menanyakan izin database kami. Saya pindah dari GrantedAuthoritiesMapper untuk melakukan ini karena dua alasan. Pertama, saya tidak menggunakan Otoritas dari LDAP jadi mengapa malah mencegatnya? Dan juga karena saya tidak tahu cara mendapatkan nama pengguna yang masuk di dalam GrantedAuthoritiesMapper. Saya mencoba menggunakan SecurityContext tetapi saya mendapat NullPointerException setiap kali saya mencoba menelepon context.getAuthentication().getName() Saya berasumsi karena pengguna belum sepenuhnya diautentikasi.

Jadi saya beralih menggunakan AuthenticationSuccessHandler. Saya mencoba menjaga logikanya tetap sama. Saya mencoba menambahkan peran ke token Otentikasi pengguna dengan authentication.getAuthorities().add(...); tetapi saya mendapatkan kesalahan karena CustomAuthority saya tidak memperluas GrantedAuthority. Itu tidak memperluasnya, tetapi mengimplementasikan antarmuka. Saya bertanya-tanya apakah ini karena itu enum, jadi saya mengubahnya menjadi kelas dan saya masih mendapatkan kesalahan. Berikut kode untuk AuthenticationSuccessHandler khusus yang saya miliki sekarang:

public class CustomAuthoritiesMapper implements AuthenticationSuccessHandler 
{
    private CustomPermissionDAO permissionsDao = new CustomPermissionDAO();

    private static final String ROLE_ADMIN = "ADMIN_ACCOUNT";

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException
    {
        List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>();

        List<DatabasePermission> permissionsForUser = permissionsDao.getPermissionByUsername(authentication.getName());

        for (DatabasePermission permission : permissionsForUser)
        {
            if (ROLE_ADMIN.equals( permission.getTag() ))
            {
                roles.add(new CustomAuthority("ROLE_ADMIN"));
            }
            //Default role for all users.
            roles.add(new DashboardAuthority("ROLE_EMPLOYEE"));
        }
        for(GrantedAuthority auth : roles)
        {
            authentication.getAuthorities().add(auth);
        }
    }
}

Saya telah mencoba hampir setiap kombinasi dari semua yang dapat saya pikirkan.. Saya telah mengubah List<GrantedAuthority> menjadi Daftar objek CustomAuthority. Saya sudah mencoba menggunakan addAll(roles) alih-alih menambahkan satu per satu.. Setiap kali saya mendapatkan beberapa variasi dari kesalahan yang sama:

Metode add(capture#1-of ? extends GrantedAuthority) dalam tipe Collection tidak berlaku untuk argumen (GrantedAuthority)

Dan kode CustomAuthority:

public class CustomAuthority implements GrantedAuthority
{
    private String name;

    public CustomAuthority(String name)
    {
        this.name = name;
    }

    public String getAuthority() {
        return name;
    }
}

Bantuan apa pun akan sangat dihargai.

Dari melihat "pertanyaan terkait" sepertinya otentikasi.getName() mungkin tidak berfungsi di sini tetapi saya ingin mencari tahu mengapa saya tidak dapat menambahkan izin yang ingin saya tambahkan ke otoritas pengguna sebelum saya mengatasi masalah itu.


person JDiPierro    schedule 12.07.2013    source sumber


Jawaban (2)


Ini bukan jawaban untuk pertanyaan awal Anda. Ini adalah proposisi tentang bagaimana hal ini dapat dilakukan dengan cara lain.

Yang terlihat tidak biasa bagi saya adalah Anda menggunakan AuthenticationSuccessHandler untuk hal-hal yang seharusnya dilakukan oleh AuthenticationManager dan AuthenticationProviders. Bayangkan dua AuthenticationProviders, satu untuk LDAP dan satu lagi untuk DB. Soalnya jika digabungkan lewat default AuthenticationManager maka yang digunakan hanya penyedia pertama. Anda dapat menyiapkan AuthenticationManager khusus dengan logika yang sedikit berbeda:

  • Ia mengetahui tentang dua penyedia
  • Itu memanggil mereka dalam urutan yang benar
  • Ini menggabungkan dua hasil autentikasi dari dua penyedia menjadi satu hasil global, mengambil kredensial pengguna dari LDAP dan otoritas dari DB.

Kekurangan: pengembang baru yang ingin menambahkan penyedia autentikasi ketiga mungkin akan terkejut dengan AuthenticationManager khusus.

Keuntungan: Saya pikir kode ini akan cocok di tempat yang tepat.

Semoga ini membantu.

person Maksym Demidas    schedule 15.07.2013

Alasan mengapa Anda tidak dapat memperoleh nama pengguna saat ini dari SecurityContext adalah karena nama pengguna tersebut belum terisi (Anda masih mencari tahu peran apa yang akan disertakan di dalamnya).

Salah satu opsinya adalah menggunakan LdapAuthenticationProvider dan LdapAuthoritiesPopulator seperti dijelaskan dalam FAQ. Berikut adalah contoh dari FAQ

public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator {
    @Autowired
    JdbcTemplate template;

    public List<GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
        List<GrantedAuthority> = template.query("select role from roles where username = ?",
                                                   new String[] {username},
                                                   new RowMapper<GrantedAuthority>() {
            /**
             *  We're assuming here that you're using the standard convention of using the role
             *  prefix "ROLE_" to mark attributes which are supported by Spring Security's RoleVoter.
             */
            public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
                return new GrantedAuthorityImpl("ROLE_" + rs.getString(1));
            }
        });
    }
}

Ini seharusnya berhasil untuk Anda karena ini memasukkan nama pengguna untuk Anda. Gunakan nama pengguna itu untuk kueri guna mendapatkan peran bagi pengguna.

Seperti yang disebutkan dalam FAQ, Anda perlu menyambungkannya ke LdapAuthenticationProvider dengan LdapAuthoritiesPopulator khusus.

Opsi lainnya adalah memasukkan UserDetailsContextMapper khusus. Standarnya adalah LdapUserDetailsMapper yang akan memberi Anda gambaran tentang cara mengimplementasikan logika.

person Rob Winch    schedule 12.07.2013
comment
Saya telah menemukan cara hack-job untuk melakukannya di SuccessHandler tetapi tampaknya ini cara yang tepat untuk melakukannya. Terima kasih telah mengarahkan saya ke arah itu. - person JDiPierro; 15.07.2013
comment
Sebenarnya.. sepertinya tidak mungkin menggunakan LdapAuthoritiesPopulator dengan ActiveDirectoryLdapAuthenticationProvider? - person JDiPierro; 15.07.2013
comment
Anda benar (jawaban saya menyatakan untuk menggunakan LdapAuthenticationProvider jika Anda ingin menggunakan LdapAuthoritiesPopulator). Alternatifnya, jika Anda ingin menggunakan ActiveDirectoryLdapAuthenticationProvider gunakan UserDetailsContextMapper. - person Rob Winch; 15.07.2013